iOS 5の位置情報まとめ - iOS Advent Calendar 17日目

昨年、MOSAのセミナーでiOS 4での位置情報について話す機会がありました。そのときの資料がSlideShareにあがってます。

http://www.slideshare.net/basuke/ios4-5698074
iOS4時代の位置情報サービスの使い方

このプレゼンを書いてから1年、OSのバージョンもあがりiOS 5になりました。今日は4から5になって変わったことを中心に、最近の位置情報サービスの使い方についてつらつらと書いていこうと思います。最後に、位置情報を使いやすくするライブラリとサンプルをご紹介します。

おさらい

位置情報には3種類の測位方法があります。

iOSの位置情報サービスにも3種類あります(上の三つとは関係なし)

  • Standard Location Service
  • Significant Location Change Monitoring
  • Region Monitoring

この三つのサービス、それぞれ利点欠点があり、前述の三つの測位方法を組み合わせてサービスを提供しています。

バックグラウンドで安心して位置情報を得たい場合には、Significant Location Change MonitoringかRegion Monitoringを有効にする必要があります。でないと、アプリがシステムによって殺された場合に(よくある)、勝手に復帰してくれません。

という程度の前提で...。ではまずiOS 5の変更点についてです。

iOS 5でのCoreLocationの変更点
iOS 5になったことで、API的に変更があったことは少ないです。

  • MapKitからGeocoderが移ってきた。正引き(住所から緯度経度)のGeocodingに対応。
  • 逆にコンパスのHeadingはCoreMotionに移動していく気配(CoreLocation側に変更はありません)

とまあ、この程度。

でも、その裏では既存の機能に大幅に改修が入っています。それはSignificant Location Change MonitoringとRegion Monitoringが、CellだけでなくWiFi「など」も使って精度と安定性を大幅に向上させたということです。WiFiを使うということは、これまで対象外だったiPad WiFiモデルや、iPod touchでもSignificant Location Change Monitoringを使うことが出来るようになったということで、実用的なアプリを作る上ではかなり大事な機能改修です。

iOS 5になって、位置情報を使ったアプリが増えてきている気がするのは、アップルがしきりにiOS 5の位置情報の性能の良さを各所で宣伝しているからだと思われます。標準のリマインダーアプリにも位置情報によるリマインド機能がつきました。今年のWWDCでも、位置情報系のラボで話を聞いてみると、ようやく使えるようになったんだ、安心して使ってくれってなことを言われた覚えがあります(それまでは何だったんだという話ですが)。

Region Monitoringについて
ということで、今年になってからいろいろと新しい機能を使ってみようと試みています。Significant Location Change Monitoringは、使い方に関して標準のサービスと変わらないので、使う場所とタイミングを調整するぐらいで話は簡単です。バックグラウンドに回ったときにはこっちに切り替えとけってぐらいだと思います。

一方、Region Monitoringのほうは、そもそもこれまでに無かったサービスで、アプリの中での使い方も含めて、ゼロから新たに考える必要がありました。なかなか時間がかかる作業でした。あまり情報も無いので、自分で試してみて挙動を知る、ということの繰り返しです。しかも、途中でOSがバージョンアップしたものですから、それまでの知識が無駄になったりやり直しだったり大変でした。

というわけで、現状はまだ模索中の状態です。結論も出てませんし自分のアプリで使うまでには至っていません。ここまでのところで気がついたことを、メモ的にまとめておきたいと思います。

まず、一番大事な精度。これが思った程よくないです。いろいろ試していると結果的には確かに機能しているようなんですが、思った精度では機能していない、というところ。僕が期待していたのは、リージョンの大きさや現在地からの距離などを総合的に判断して、LocationManagerの精度を勝手に調整してくれて、バッテリと精度のトレードオフを気にしないで使える出来るヤツ、を期待していたのですが、どうやらそんな甘いことはなさそうです。

あと、領域に入ったことと抜けたことは知らせてくれるんですが、今入っているのかどうかを調べる手段が無いというのもちょっと困り者です。得られる位置情報で自分で調べればいいと言えばそれまでですが、Region Monitoringがどう判断しているかちゃんとはわからないので、位置情報から得られた情報からUIを構成しても、通知でやってくる結果と食い違ってしまうことがあります。特に設定したての時。これはちょっと困るんです。

Region Monitoringに限ったことではないですが、他の位置情報系のアプリやサービスしだいで精度がばんばん変わってしまいます。例えば、Apple純正のサンプルにRegionsという、まさにRegion Monitoringの使い方のサンプルがあるんですが、このアプリ、同時に標準Location Serviceも有効にしていて、さらに精度を最大に要求する設定になっています。それはずるですよw。精度最大にし続けていいのなら、誰も苦労はしないんです。案の定、要求精度を下げるとあまり引っかからなくなります。困ったもんです。

ということで、Region Monitoringを使うのはもうちょい先になりそうです。

位置情報系のサンプル、集大成を目指して
さて、いろいろ位置情報調べていくのは大変だと言うことを書いてきましたが、実際のアプリで試すことはもちろん大事なのですが、他の問題と切り離してテストすることもそれはそれで大事です。そんな目的で、サンプルを書き始めました。GitHubに置いてあります。

https://github.com/basuke/BSKLocations

出来ることはシンプルなロギングです。サンプルとしては一通りCoreLocationの機能を使い倒しています。

メインとなるのはBSKLocationManagerです。CLLocatinoManagerに変わるものです。特徴は以下の通り。

  • シングルトン形式で[BSKLocationManager sharedManager] で呼び出せる
  • delegateではなくNotificationで返すので、複数の場所から共有できる
  • アプリがアクティブでない状態で位置情報が必要なければ自動的に切る設定

さらにBSKLocationClientオブジェクトを使うと、位置情報が必要な複数の場所で、好きにdesiredAccuracyやdistanceFilterを設定して、それらをまとめて一番要求の高いものを自動的にセットしてくれる機能も実現できます。地図画面で一時的に最大精度で緯度経度が欲しい、でも他の場所では緩い精度で十分、そのかわりバックグラウンドでも機能させたい、それらは設定で簡単に切り替えられる、なんてアプリを作りたいとします。状態の管理が面倒なので、たぶん複数のCLLocationManagerを作ることになると思います。

僕は前からアプリにはCLLocationManagerは一つでいいのではないか、と主張している派です。位置情報の使用許可もアプリ単位です。アプリの特定の機能に対して許可をする訳ではない。そうすると、purposeプロパティにはアプリケーションワイドに通用する文言を書かないと行けない。それをあちこちでやるのは変なのではないか?という思いがキッカケです

このBSKLocationManagerとBSKLocationClientのセットを使うと、その辺うまくやってくれて非常に便利です。サンプルでは、ログの収集と地図画面での現在地取得の二カ所で別々に独立して位置情報を取得しています。

ちなみに各サービスを日本語で表すと
書いている途中で、この長ったらしい英語の名前は何とかならないものかと調べたところ、日本語が結構 orz な感じだったので英語で通しました。以下、各サービスの日本語訳です。

  • Significant Location Change Monitoring Service = 大幅変更位置情報サービス
  • Standard Location Service = 標準位置情報サービス
  • Region Monitoring Service = 領域観測サービス

出典はここ。
http://developer.apple.com/jp/devcenter/ios/library/documentation/LocationAwarenessPG.pdf

僕はこの訳は使わないと思いますw