What's new in location
要点
iOS14以降は、
・位置情報精度について、full、reducedの2パターンが追加され、どちらの値だったとしてもアプリ側が対応できるようにしておく必要がある。
・full精度ではないとできないような機能がある場合、「一時的なfull精度の許可」を求めるか、「設定アプリにユーザーを飛ばして設定を変更してもらう」という対応のどちらかにすると良い。
・必要もないのにfull精度の許可をユーザーに求めるような事は適切でない。reduced精度をデフォルト設定とする事もできるので、選択肢の一つとして考えるべき。
詳細
iOS13以降では、位置情報取得の可否についてユーザーは許諾ダイアログまたは設定アプリから3通りの選択肢を選ぶことができた。
- Never(取得不可)/ While Using(アプリ使用中のみ取得可)/ Always(常に取得可)
 
※ Always(常に取得可)は最初の許諾ダイアログでいきなり選択することができるわけではなく、「Once(一回許可)」を押した後、少し時間が経ってから常に取得可能に変更するかどうか尋ねるダイアログが出現する形式であった。
→ アプリの種類によっては、非常に正確な位置情報がいるもの(地図アプリなど)と、位置情報の精度はユーザーの好みに任せていいもの(SNS、マッチングアプリなど)がある。つまり取得する情報の精度をコントロールできた方がいい。そのため、iOS14以降から、**Precise(精度)**という項目が位置情報許諾ダイアログ並びに設定アプリに追加され、正確な位置情報まで送るかどうかを選べるようになった。(**Full(正確な位置情報)**か、**Reduced(大まかな位置情報)**の二択)
※見ればわかるように、精度のほかユーザーがいる地点周辺の地図も一緒に表示されるようになった。
これに合わせて、CLLocationManagerクラスのauthorizationStatusメソッドは廃止予定になり、以下の列挙形で位置情報精度を表すようにする。
var accuracyAuthorization: CLAccuracyAuthorization { get }
enum CLLAccuracyAuthorization {
   case fullAccuracy
   // 正確な精度で位置情報を提供する事をユーザーが許可した場合。iOS13以前はこれしかなかったのと同じ状態。
   case reducedAccuracy
   // 大まかな精度でのみ位置情報を提供する事をユーザーが許可した場合。
}
またCLAuthorizationStatusかCLAccuracyAuthorizationのどちらか一方でも変更があった場合、以下の新規追加されたデリゲートメソッドが呼ばれるようになった。
locationManager(_:didChangeAuthorization:) //deprecated
locationManagerDidChangeAuthorization(_:) //新規追加(iOS14以降)
//使用例
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
 switch manager.authorizationStatus {
   case .authorizedAlways, .authorizedWhenInUse:
      //フラグON
      self.hasSomePermission = true
   case .notDetermined, .denied, .restricted:
      //フラグOFF
      self.hasSomePermission = false
   default: 
      print("Unhandled case")
 }
 switch manager.accuracyAuthorization {
    case .reducedAccuracy: 
       self.gettingExactLocation = false
    case .fullAccuracy:
       self.gettingExactLocation = true
   default: 
      print("This should not happen!")
 }
}
-> 従来位置情報を使用していたアプリについて、accuracyAuthorizationがどちらの値になっても対応できるようにする必要がある。
- 
位置情報は従来通り、
locationManager:didUpdateLocations:メソッドでCLLocationクラスオブジェクトとして渡されてくる。これは1時間に4回ほどアップデートされるのだが、精度がfullAccuracyの場合、ユーザーのいる代表的な座標と考えるのではなく、ユーザーが本当にその時点でいる座標として取り扱うこと。 - 
AppleのMapアプリも
reducedAccuracyをサポートする形でアップデートされる。具体的には、ユーザーの位置は青い点ではなく、大まかな位置を示す円で表されることになる。 - 
fullの精度が必要なのに、reducedの精度の取得許可しかユーザーから得られていない場合どうするか。- 設定アプリへ飛ばし、設定を変更するようユーザーに促す。ただユーザーにとって面倒な動作なので、あまりやりたくはない。
 - 新しいメソッドの
requestTemporaryFullAccuracyAuthorization(withPurposeKey:completion:)を使い、一時的にfull精度の位置情報取得を行う許可を得ることが可能。この後は、位置情報そのものの許可ダイアログで「Once(一回許可)」を押した時と似た振る舞いとなり、次にアプリを起動した際、full精度の位置情報取得を恒久的に許可するかのダイアログがユーザーに表示されることとなる。 
 
@IBAction func userWantsToNavigate(_ sender: Any) {
   
   //`reduced`の精度の取得許可しかユーザーから得られていない
   if manager.accuracyAuthorization = .reducedAccuracy {
      //一時的な許可をユーザーに求める
    //puroposeKeyとは、InfoPlistの NSLocationTemporaryUsageDescriptionDictionaryの中にあらかじめ記載した、キー文字列。
      manager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: "WantsToNavigate") {
         
          //許可が得られた場合
          if self.manager.accuracyAuthorization = .fullAccuracy {
             self.beginNavigation()
          } 
      }
   } else {
      self.beginNavigation()
   }
}
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
   <key>WantsToNavigate</key>
   <string>歩行ルートを計算するために正確な位置情報が必要です。</string>
   <key>HogeHoge</key>
   <string>HogeHogeするために正確な位置情報が必要です。</string>
</dict>
- 
方針
- 精度が
reducedの場合、AppleのMapアプリのように、それをUIに反映させることが推奨される。例えば、精度がreducedの場合はユーザーの大まかな位置を円で表す・現在の精度が何かをラベルで表示するなど。これにより、reducedでもアプリが対応できるようにし、必要もないのに常にfull精度を要求する事は止める。 - 精度が
fullでないと使えない機能がある場合(Mapアプリでいうルート検索機能など)は、上で書いたように一時許可を求めても問題ない。Mapアプリは、このような一時許可を求める形式を取っている。 
 - 精度が
 
精度がreducedが適用され、低い精度にしても多くの距離を移動したと判定できる場合のみ通知される。同じ場所に止まっていると判定できる場合は、従来通り通知しない。
やはり精度reducedが適用される。通知されるタイミングについてはfullでも変わらないが、通知される場所が大まかなものになる(例えば、fullなら「◯○公園に到着」と通知される所、rducedでは「××市に到着」となる等)。
精度reducedでは使用できない = 常にfull精度の位置情報が必要。
例として、Apple公式のReminderアプリでは、特定のエリアを起点にしてリマインドを行う機能がある。これはRegion Monitoringにより行われている。
Reminderアプリのこの機能では、常にfull精度の位置情報を要求し、reduced精度では意味をなす動作ができない。このことから、上に述べたMapアプリのような、一時的にfull精度を求めるような事はせず、端的にユーザーに設定アプリに飛んでfull精度を許可するよう促す形式を取っている。
このように、設定アプリに飛んで設定変更を促すという動作を自作アプリでしたい時は、果たして適切かどうかを考える必要がある。
- 
full精度の許可が得られているものの、実際にはreduced精度しか必要がない場合- このような場合は、
LocationManagerクラスのdesiredAccuracyに、kCLLocationAccuracyReducedというiOS14からの新しい値をセットする。 
 - このような場合は、
 
var locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyReduced
- そもそも
reduced精度しか許可を求めない場合 
<key>NSLocationDefaultAccuracyReduced</key>
<true/>
Info.plistに上記のように記載すると、Reduced精度のみ許可を求めるようになる(精度を選ぶボタンが表示されなくなる)。
ただ、この設定をしてもSettingsアプリからfull精度を選択する事はなお可能となっている。
Apple公式の TVアプリでは、視聴できる番組を制限するためユーザーの地域を知る必要があり、位置情報を取得している。ただどの国にいるかなど大まかな位置だけ知れれば良いために、この機能を利用している。
- 
reduced精度の裏側の実装 
reduced精度は、「ユーザーの本当の位置の周りにノイズを付加する」というような方法で算出されるのではない。地面をあるエリアごとに分け、1時間におよそ4回ほど、ユーザーがどのエリアにいるかを計測して行っている。1エリアの大きさは都市地域では数キロごとだが、人口がまばらな地域では10キロを超えることがある。このように大まかなエリアごとの区分けでしかないため、実際にいる市の隣の市にいると判定されることもありうる。
- Watch Appとの連携
 
Apple Watchのコンパニオンアプリ内で制度に関する許可をした場合、これと連動するiPhoneアプリでも自動的に許可が適用される。
参考

