WatchKitで現在位置の地図を表示する


WatchKitでは静的な地図を表示することができます。
残念ながら、スワイプやピンチなどで移動拡縮ができるような動的な地図はありません。

ここではGPSを使って現在地の地図を表示する方法を説明します。
なお、WatchにはGPSはついていないのでiPhoneのGPSを利用することになります。(ここ大事です)

位置情報を取得するのに使用するCoreLocationの詳細については、
リファレンスか別の記事を参照してください。

## とりあえず地図を表示してみる
`WKInterfaceMap`クラスを使用して下記の手順で地図を表示することができます。

1. ストーリーボードでViewにMapを追加
1. Mapのアウトレットを作成
1. 緯度経度を指定

```swift
@IBOutlet weak var map: WKInterfaceMap!

override init() {
    super.init()
    // 座標の指定
    let coordinate = CLLocationCoordinate2DMake(37.331667, -122.030833)
    let span = MKCoordinateSpanMake(1.0, 1.0)
    let region = MKCoordinateRegionMake(coordinate, span)
    map.setRegion(region)
}
```

ここではApple本社の場所を指定してみました。

## 現在地の地図を表示してみる
GPSから位置情報を取得して設定するだけなんですが、
iOS App側で位置情報を使用する設定をしてあげないといけません。
この設定をするのはWatch Extensionではなく、iOS App側です。

### iOS App側の設定
位置情報を使用する設定を行います。

#### Info.plistに位置情報を使用する目的を設定
![NSLocationDescription.png](https://qiita-image-store.s3.amazonaws.com/0/45742/f4104d84-2556-03b1-87eb-168c39cd9b61.png "NSLocationDescription.png")

こんな感じで下記２項目をInfo.plistに追加します。

* NSLocationWhenInUseUsageDescription
* NSLocationAlwaysUsageDescription

なお、今回の例だと2番目の項目だけでも動くかと思います。

#### iOSアプリを起動して位置情報へのアクセスを許可する

```swift
var locationManager = CLLocationManager()
    
override func viewDidLoad() {
    super.viewDidLoad()

    // 位置情報へのアクセスを要求する
    locationManager.requestAlwaysAuthorization()
}
```
これでiOS Appを起動すると、アクセス許可の確認がでるので許可します。

---
追記(2015/2/20)
CLLocationManagerの変数をメソッド内で定義してインスタンスを作ると
確認ダイアログが出ない可能性があるとのことなので修正しました。
@SatoTakeshiX さん、ご指摘ありがとうございます！

---

### Watch Extension側の設定
#### 位置情報を取得するコードを書く

```swift
import WatchKit
import Foundation
import CoreLocation

class InterfaceController: WKInterfaceController, CLLocationManagerDelegate {
    @IBOutlet weak var map: WKInterfaceMap!
    
    var locationManager = CLLocationManager()
    
    override init() {
        super.init()
        
        locationManager.delegate = self
        
        if CLLocationManager.locationServicesEnabled() {
            switch CLLocationManager.authorizationStatus() {
            case .AuthorizedAlways, .AuthorizedWhenInUse:
                locationManager.startUpdatingLocation()
                break
            default:
                break
            }
        }
    }

    func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        let lat = newLocation.coordinate.latitude
        let lng = newLocation.coordinate.longitude
        let coordinate = CLLocationCoordinate2DMake(lat, lng)
        let span = MKCoordinateSpanMake(1.0, 1.0)
        let region = MKCoordinateRegionMake(coordinate, span)
        map.setRegion(region)
    }
}
```

### 確認してみる
もちろん実機は無いのでシミュレータで確認します。
`メニュー ＞ Debug > Location > Custom Location...`で
緯度経度を変更するとWatch Appに反映されることが確認できると思います。

|地名|緯度|経度|
|:-----------|:------------:|:------------:|
|APPLE Inc.|37.331667|-122.030833|
|東京駅|35.681382|139.766084|
|モン・サン＝ミシェル|48.636063|-1.511457|

例は最低限のコードなのでなんども更新がかかるなど問題はありますが
とりあえず現在地の地図を表示することはできました。

## まとめ
WatchKitで位置情報を扱う時は、iOS Appで位置情報へのアクセス許可を行う必要がある。

参考：
[WatchKit Framework Reference > WKInterfaceMap Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceMap_class/index.html#//apple_ref/occ/cl/WKInterfaceMap)
[iOS 8から位置情報を取得する方法が変わるよ](http://qiita.com/koogawa/items/6ec24ca3201977e9642b) -[@koogawa](http://qiita.com/koogawa)さん