iOS 8から位置情報を取得する方法が変わるよ

![top.png](https://qiita-image-store.s3.amazonaws.com/0/8292/02fa9a4a-95c1-cbd3-a7b1-236586cc68d4.png)
（[WWDC 2014 発表資料](https://developer.apple.com/videos/wwdc/2014/?id=706)より引用）

## つまりどういうこと？

iOS 8 から位置情報の取得方法が変わるようです。今までの方法だと<b>位置情報が取れなくなります</b>。（すでにAppStoreに並んでいるアプリについてはこの限りではありません）

[iOS 8 : Location Services not working ](http://stackoverflow.com/questions/24062509/ios-8-location-services-not-working)

> My app that worked fine in iOS 7 doesn't work with the iOS 8 SDK.
>
> CLLocationManager doesn't return a location, and I don't see my app under >Settings > Location Services either. I did a Google search on the issue but nothing >came up, what could be wrong?

▲Stack Overflowにもこの事に関する質問が寄せられていました

## ポイント

* 位置情報に対するプライバシーを、ユーザがより細かく設定できるようになりました（今までは許可する/しないの2択）
  * 使用中のみ許可 (WhenInUse)
  * 常に許可 (Always)
  * 許可しない (Never)
* 位置情報の使用目的を記載するのが<b>必須になった</b>
* 位置情報の認証リクエストするためのメソッドが増えた


## 何をすればよいのか

まずは `Info.plist` 内に<b>位置情報を使用する目的</b>を記載します。この項目は今まで任意でしたが、iOS 8からは<b>必須</b>になりました。

![](http://cdn-ak.f.st-hatena.com/images/fotolife/k/koogawa/20140812/20140812132005.png)
（[WWDC 2014 発表資料](https://developer.apple.com/videos/wwdc/2014/?id=706)より引用）

キー名はプライバシーポリシーによって異なります。

<table>
<tr><th>使用中のみ許可</th><td>NSLocationWhenInUseUsageDescription</td></tr>
<tr><th>常に許可</th><td>NSLocationAlwaysUsageDescription</td></tr>
</table>



### 認証ステータスをチェック



認証ステータスも種類が増えてます。


* kCLAuthorizationStatusNotDetermined
* kCLAuthorizationStatusRestricted
* kCLAuthorizationStatusDenied
* kCLAuthorizationStatusAuthorized (<span style="color: #ff2600">deprecated</span>)
* <b>kCLAuthorizationStatusAuthorizedAlways</b>
* <b>kCLAuthorizationStatusAuthorizedWhenInUse</b>


`kCLAuthorizationStatusAuthorized` が<b>非推奨</b>になり、`kCLAuthorizationStatusAuthorizedAlways`（常に許可されている）、`kCLAuthorizationStatusAuthorizedWhenInUse`（使用中のみ許可されている）が増えています。

iOS 8で位置情報が取れない場合は、この認証ステータスが `kCLAuthorizationStatusNotDetermined` になっている可能性があります。


現在の認証ステータスは次のデリゲートでチェックできます。

Objective-C:

```objc
// CLLocationManager オブジェクトにデリゲートオブジェクトを設定すると初回に呼ばれる
- (void)locationManager:(CLLocationManager *)manager
     didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    if (status == kCLAuthorizationStatusNotDetermined) {
        // ユーザが位置情報の使用を許可していない
    }
}
```

Swift:

```swift
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status {
    case .NotDetermined:
        // ユーザが位置情報の使用を許可していない
    }
}
```

ユーザが位置情報の使用を許可していない場合は、次に説明する<b>認証リクエスト</b>を使って位置情報の使用許可を要求します。

### 認証リクエスト


iOS 8 から CLLocationManager に次のメソッドが追加されています。

* requestAlwaysAuthorization - 位置情報の使用を<b>常に許可</b>してもらうよう要求
* requestWhenInUseAuthorization - 位置情報の使用を<b>アプリ起動時のみ許可</b>してもらうよう要求


<span style="color: #ff2600">※iOS 7環境でこのメソッドを呼ぶと当然クラッシュするので注意！</span>

このメソッドを呼ぶことで、認証ダイアログが表示されます。ダイアログには最初に設定した「位置情報を使用する目的」も表示されます。

![](http://cdn-ak.f.st-hatena.com/images/fotolife/k/koogawa/20140812/20140812132707.png)
（[WWDC 2014 発表資料](https://developer.apple.com/videos/wwdc/2014/?id=706)より引用）

このメソッドは何度でも呼ぶことができますが、認証ダイアログが表示されるのは認証ステータスが `kCLAuthorizationStatusNotDetermined` になっているときだけのようです。

ここで許可されることで、ようやく位置情報が取れるようになります。


## 対応しないとどうなるの？

AppStoreに上がっているアプリ（上記の対応をしてない）をダウンロードし、iOS 8で実行してみた場合の挙動を書こうと思ったのですが、NDAに抵触しそうなのでまた後日書きたいと思います。

**2014/9/12追記**：すでにAppStoreに並んでいるアプリをダウンロードし、iOS 8で実行した場合は、これまで通り位置情報を取得することができます。よって、昔リリースしたアプリがiOS 8対応してないので急に位置情報が取れなくなった！ということはありません。

## 参考になるリンク

   * [What’s New in Core Location](https://developer.apple.com/videos/wwdc/2014/?id=706) - WWDC 2014 発表資料（PDF）
   * [iOS 8 : Location Services not working ](http://stackoverflow.com/questions/24062509/ios-8-location-services-not-working) - Stackoverflowに寄せられた質問
   * [iOS 8 の位置情報のプライバシー設定に対応する](http://im-sei.tumblr.com/post/91824653043/ios-8) - Swiftのサンプルコード付きで詳しく解説されています

----
本記事は http://blog.koogawa.com/entry/2014/08/12/191215 でも公開しております。