位置情報を正確にトラッキングする技術 in iOS — (第2回)位置情報の取得
ここからはiOSアプリでの位置情報取得の方法をステップごとに説明して行きます。まずはXcodeでSingle View Applicationのプロジェクトを作成してから以下の説明に進んでください。(このブログの最後にサンプルプロジェクトのGitHubのリンクがあります。)
まずは下のようにCoreLocation frameworkをプロジェクトに追加します。
このframeworkを使うためにはSwiftのコードでCoreLocation frameworkをインポートします。
このチュートリアルでは、CoreLocation周りの処理をハンドルするクラスLocationServiceクラスを作ってこちらに位置情報取得処理を一任します。下のように LocationServiceクラスの中でCoreLocationをインポートしてください。
これ以外にコードの外でやらなければいけない設定が1つあり、忘れやすいので先にやっておきます。
Info.plistの中にUIRequiredDeviceCapabilitiesというkeyがあり、これに”gps”と”location-service”という文字列を足します。
このフラグを設定すると、GPSの機能やLocation Serviceの機能(GPSよりは少し上のレイヤー)を持っていない機種からアプリがダウンロードできなくなります。iPod TouchなどGPSを備えていない機種でアプリをインストールしたユーザーがアプリの機能を使えないといったトラブルを防ぐためにもこのフラグを設定しておいたほうがいいでしょう。
UIRequiredDeviceCapabilitiesはPlistのビューでは“Required device capabilities”となっています。
Location Managerを初期化する
LocationServiceクラスの中でCoreLocation frameworkで最も重要なLocationManagerというクラスのインスタンスを初期化します。
CLLocationManagerクラスのインスタンスを所得した後、desiredAccuracy (求める精度のレベル)にkCLLocationAccuracyKilometer(〜1km)の制度を設定します。(desiredAccuracyについては次回のブログでさらに詳しく説明します。)
次にユーザーに位置情報へのアクセスを承認してもらう(Authorizationという言葉を使います)ためのコードを追加します。
位置情報へのアクセス要請には以下の2つのレベルがあります。
requestWhenInUseAuthorization
- ロケーションサービスをフォラグラウンドから起動することをアプリに許す。(位置情報を取り始めるのは必ずアプリがフォラグラウンドに入る時で、ユーザーがスタートボタンを押した時などに取り始める)
- バックグラウンドからでも位置情報の取得をアプリに許可する。
requestAlwaysAuthorization
- バックグランドからでもロケーションサービスをスタートすることを許す。つまりPush通知などをトリガーにしてバックグランドでユーザの位置情報をとり始めることができるようにする。
通常ランニングアプリなどであればバックグラウンドにアプリがいる状態から新たに位置情報のトラッキングを始めることはないので、多くの場合requestWhenInUseAuthorizationの許可があればいいと思います。
requestAlwaysAuthorizationだと下のように”ユーザーがアプリを使ってない時でも位置情報にアクセスしていいですか?”というようなかなりユーザーが身構えてしまう内容のアラートになります。
requestWhenInUseAuthorization だと下のようにもっとマイルドな表現にアラートになります。
このアラートのメッセージ部分の文言はInfo.plist中にNSLocationWhenInUseUsageDescriptionというKeyで追加できます。”Privacy — Location When in Use…”というところが該当の箇所になります。ここのValueに入れた文字列が表示されます。
位置情報の取得
次にCLLocationManagerDelegateを実装します。
位置情報の取得は非同期的なプロセスを経て行われます。まずアプリがCoreLocationに位置情報の取得を要求し、CoreLocationのミドルウェアがGPSデバイスドライバーに位置情報の取得を要求します。そしてGPSデバイスドライバーがGPSチップに位置情報の取得を要求します。この後GPSチップが衛星や基地局とのやりとりで位置情報を取得できたタイミングでGPSドライバーをコールバックして位置情報を渡します。この情報がCoreLocation経由でCLLocationManagerDelegateのプロトコルメソッドに返ってきます。
このようにして位置情報を取得するためLocationServiceクラスにCLLocationManagerDelegateを実装するように宣言します。(下のコードの1行目)
次にこのプロトコルの関数であるdidUpdateLocationsメソッドを実装します。ここに先ほど説明したコールバックチェーンを介して取得された位置情報がarrayできます。このarrayの最後のアイテムが最も新しい新鮮な位置情報です。これはCLLocationというクラスのオブジェクトです。これを取り出してlatitudeとlongitudeの値を取り出します。
CLLocationクラスのオブジェクトはcoordinateというオブジェクトを持っていてこれがlatitudeとlongitudeという値を持っています。サンプルではこのlatitudeとlongitudeの値(Double型)をログに出力しています。
iOSシミュレーターを使ったテスト
ここまで実装した位置情報取得機能をテストするためにアプリを実機にインスールしてGPSがキャッチできる屋外に出る必要はありません。
iOS シミューレーターにダミーの位置情報をアプリに供給する便利な機能があります。Debug -> Locationと進み、そこで見えるオプションからCity Runを選びます。こうするとシミュレーターが街中をジョギングしている場合の位置情報の変化を擬似的に再現してその位置情報をアプリに送ってくれます。
アプリを実行し、City RunをシミュレーターのDebug->Locationメニューから選んでください。ログに下のように緯度、経度が出力されているのが見えるようになります。
以上が位置情報をiOSアプリで取得する方法です。
下がここで説明したサンプルアプリのコードです。
https://github.com/mizutori/iOSLocationStarterKit
このコードには次章以降で説明する様々な機能お追加されていますので5b7f7fd5a54bdce0b10b978b97ae52391422dd6b というSHA-hashのcommitを見せてください。このコミットにはここまでで説明下内容しか入っていません。
次回は、精度の高い位置情報を取得するための設定、バックルグラウンド状態で位置情報の取得方法、バッテリ消費に対する考え方に関してさらに深く説明していきます。
このブログの内容に関する質問や位置情報トラッキング機能開発に関する相談などはこちらにご連絡ください。
@mizutory
[email protected]