[iOS]近年の位置情報とプライバシー
iOS 12〜iOS 17までの、位置情報とプライバシーについて時系列で書いておきます。
※この記事ではiOSかつ本体(App ClipsやWidgetではない)におけるプライバシーについての記事です。
〜iOS 12
「使用中のみ許可」の権限を求める場合は NSLocationWhenInUseUsageDescription
、 「常に許可」の権限を求める場合は NSLocationAlwaysAndWhenInUseUsageDescription
をInfo.plistに書く。そうすると位置情報の許諾ダイアログのメッセージにその文言が表示される。
iOS 13
※スクショ、コードはWhat's New in Core Locationより引用
iOS 12までは「常に許可」「使用中のみ許可」「許可しない」の3つの選択肢だった。iOS 13から、「使用中のみ許可」「一時的に許可」「許可しない」の3つの選択肢になった。たとえ requestAlwaysAuthorization
をしても「常に許可」は最初出てこないが、なくなったわけではない。「常に許可」を求めるタイミングが変わっただけ。
使用中のみ許可
最初のダイアログで「使用中のみ許可」を選択すると、仮の「常に許可」状態になる。この時設定アプリでは「常に許可」になっている。次にバックグラウンドで位置情報の取得が走った時、ユーザに対して「常に許可」をするかどうかを問うことになる。このダイアログは1度だけ出る。
...とWWDC19の時点では発表されていたが、iOS 13.4からは「使用中のみ許可」が選択された直後に「常に許可」するかどうかのダイアログを出して聞くこともできるようになった。(以下はWWDC20の動画のスクショ)
また、iOS 12まではユーザが「使用中のみ許可」「常に許可」を選択した時にできることは以下の通りだった。
これがiOS 13からはシンプルになった。
「使用中」の定義については、 allowsBackgroundLocationUpdates=false
で locationManager.startUpdatingLocation()
するとForeground起動中が「使用中」に当たり、
allowsBackgroundLocationUpdates=true
で locationManager.startUpdatingLocation()
するとBackground起動中も「使用中」に当たる様子。
1度だけ許可
iOS 12ではこのような状態遷移だった。
iOS 13ではこうなった。
「一時的に許可」状態で設定アプリを確認すると、「次回確認」のステータスになっている。
iOS 14: 正確な位置情報
※スクショ、コードはWhat's new in locationより引用
概要
最小限の情報提供で済むよう、「正確な位置情報」のオンオフ機能ができた。この機能はアプリ側でオプトアウトすることはできない。表示は以下の通り。
オン | オフ |
---|---|
「正確な位置情報」は設定からも確認できる。
正確な位置情報がいらない場合
正確な位置情報を必要としないことがわかっているアプリの場合は、Info.plistで次のように書くと、「正確な位置情報」のオプションが非表示になる。
<key>NSLocationDefaultAccuracyReduced</key>
<true/>
基本実装
「正確な位置情報」のenumはこちら。
enum CLAccuracyAuthorization {
case fullAccuracy
case reducedAccuracy
}
権限のステータスチェックの例は以下の通り。
switch manager.authorizationStatus() {
case .authorizedAlways, .authorizedWhenInUse:
// 位置情報の使用を許可している
case .notDetermined, .denied, .restricted:
// 位置情報の使用を許可していない
default:
//
}
switch manager.accuracyAuthorization {
case .fullAccuracy:
// 正確な位置情報の使用を許可している
case .reducedAccuracy:
// 正確な位置情報の使用を許可していない
default:
//
}
delegateは以下を使うよう変更すると良い。こうすることによって、 authorizationStatus
が変わったときだけでなく、 accuracyAuthorization
が変わったときも検知できる。
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)
// ↓こちらに変える
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager)
一時的に正確な位置情報を要求する
もし正確な位置情報が必要な機能(例:道案内)なのに「正確な位置情報」がオンになっていない場合は
- 設定アプリから(ずっと)正確な位置情報をオンにしてもらう
- Core Location APIを使って一時的に正確な位置情報をオンにしてもらう
の2つの選択肢が考えられる。後者の場合は以下のメソッドを使えば良い。
func requestTemporaryFullAccuracyAuthorization(withPurposeKey purposeKey: String, completion: ((Error?) -> Void)? = nil)
func requestTemporaryFullAccuracyAuthorization(withPurposeKey purposeKey: String)
例えばPurposeKeyを「WantsToNavigate」にした場合、次のinfo.plistを設定することでユーザに「正確な位置情報」の必要性を説明できる。
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>WantsToNavigate</key>
<string>Your precise location will be used to calculate a route and allow you to use turn-by-turn directions.</string>
</dict>
ユーザにはこのような形で見える。
ここで許可をすると、iOS 13からある「一度だけ許可」と同じ状態になる。
バックグラウンドでの位置情報の取得
「正確な位置情報」がオフでも機能する。1時間に約4回位置情報をアップデートする。ただし、居場所にさほど変化がなければ重複通知はしない。リマインダーで「会社を出た時に買い物をする」のような地域リマインダーを設定する場合は、正確な位置情報の設定をオンにする必要がある。
「正確な位置情報」がオンでも不要な時は使わないようにしたい場合
「正確な位置情報」の許諾を得ているものの、実際にはそこまでの精度はいらない場合は以下のコードを書く。
var locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyReduced
「正確な位置情報をオフにする」とは
オフの状態はオンの状態にノイズが加わっただけという話ではない。情報の量子化として考えれば良い。
車の位置が実際の位置情報だとすると、オフの場合は次のような円で表せる。ただし、スナップ量は異なる。高密度の市街地では数kmの円だが、密度の低い郊外では10kmくらいの円になる(量子化範囲の標準値は半径約5km)。
また、オフの状態では1時間に約4回位置情報が再計算されるので、車の速度によっては量子化のスナップにラグが生じる。円の中心はユーザの位置というわけではなく、ユーザの近似地域の中心にすぎない。
iOS 15: LocationButton
今までの位置情報の権限取得だと「一度だけ許可」の場合、アプリをバックグラウンドにしたときに許可がなくなってしまうなどの問題があった。これを解消する形でSwiftUIでは LocationButton
が、 UIKitでは CLLocationButton
が登場した。「必要なときに一度だけ位置情報の利用を許可してもらう」が簡単にできるボタンになっている。
- このボタン自体には位置情報を取得する機能はないので、自分で
CLLocationManager
などを使って位置情報を取得する処理を書く必要がある - 過去に位置情報の使用を拒否したユーザーがLocationButtonを押すと許可ステータスが
NotDetermined
に戻り、再び位置情報を提供するかどうか選択する機会が得られる - このボタンを使う場合は、Info.plistに
NSLocationWhenInUseUsageDescription
などの許諾メッセージを設定する必要はない
実装コード
ボタンタイトルはいくつかのパターンから選ぶことになる。
LocationButton.Title | 文言 |
---|---|
currentLocation | Current Location |
sendCurrentLocation | Send Current Location |
sendMyCurrentLocation | Send My Current Location |
shareCurrentLocation | Share Current Location |
shareMyCurrentLocation | Share My Current Location |
labelStyle
プロパティを使えば、アイコンのみ、タイトルのみのボタンを作ることもできる。
labelStyle | コード | 見た目 |
---|---|---|
.iconOnly | ||
.titleOnly |
UIKitの場合はこのようになる。
let button = CLLocationButton()
button.label = .currentLocation
button.addTarget(self, action: #selector(showNearByParks), for: .touchUpInside)
@objc func showNearByParks() {
// CLLocationButtonを使うことで↓このコードが不要になった
// self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
iOS 16
位置情報を使用したアプリが起動中の場合、コントロールセンターの上部に青矢印アイコンとアプリ名が表示される。タップすると詳細が表示される。
関連リンク集
参照動画
- Meet the Location Button / WWDC21
- What's new in location / WWDC20
- What's New in Core Location / WWDC19
Discussion