[iOS] 位置情報の取得

2016.02.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

iOSでは、簡単なコードで位置情報(経緯度)を取得することが可能です。

すでに周知済みかと思いますが、iOS8以降、プライバシー向上のため、やや利用方法が変わっています。 今回は、ちょっとこの辺をまとめておく事にしました。

2 実装

実装の手順としては、次の通りです。

  • フレームワークの追加
  • 認証リクエスト
  • 利用目的の記載
  • 情報更新開始
  • 取得データの処理

それでは、各項目について見ていきます。

(1) フレームワークの追加

CLLocationManagerを使うにはCoreLocation.frameworkを追加する必要があります。

フレームワークの追加の要領は、次の通りです。

最初に、Xcodeのプロジェクト画面からGeneralLinked Frameworks and Librariesの[+]をクリックします。

A001

表示されたダイアログでは、検索窓に CoreLocationと入力し、CoreLocation.frameworkを選択して追加します。

A002

ヘッダファイルに以下のような記述をすれば、CLLocationManagerが使用可能になります。

#import <CoreLocation/CoreLocation.h>

(2) 認証リクエスト

iOS8以降では、CLLocationManager に新しく追加された認証リクエストAPIを呼び出す必要があります。

認証リクエストAPIには、使用用途に応じて次の2種類があります。

  • requestWhenInUseAuthorization (起動時のみ)
  • requestAlwaysAuthorization (常時)

最初のrequestWhenInUseAuthorizationは、アプリまたは、その機能が画面上に表示されている時だけ、位置情報の利用を許可するもので、アプリがバックグラウンド状態の時は、許可されません。

そして、次のrequestAlwaysAuthorizationは、バックグラウンドで実行中の場合にも位置情報の利用を許可するものです。

なお、このAPIを呼び出すと、ユーザに許可を求めるダイアログが表示され、ここでユーザが許可した場合のみ位置情報の利用が許可されます。

認証リクエストを使用している様子は次のようになります。

if (nil == self.locationManager) {
    self.locationManager = [[CLLocationManager alloc] init];
    // iOS8以上
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
            // アプリ起動時のみの位置情報を取得の許可を得る
            [ self.locationManager requestWhenInUseAuthorization];
        }
    }
}

※当然ですが、iOS7でこの新設されたメソッドを呼ぶと、当然クラッシュしますので注意してください。

A004

この認証APIは、何度でも呼び出すことができますが、ダイアログが表示されるのはステータスがNotDetermined(未設定)の時だけです。 したがって、一度ダイアログが表示されてユーザが「許可する/しない」の選択をした後は、このメソッドを呼び出しても何も起こりません。

(3) 利用目的の記載

先の認証リクエストを呼び出すためには、「位置情報を利用する目的」をInfo.plistに記載する必要があります。

A003

requestWhenInUseAuthorizationを使用する場合は、 NSLocationWhenInUseDescriptionに、requestAlwaysAuthorizationを使用する場合は、NSLocationAlwaysUsageDescription に、それぞれ記述が必要です。

この記載がないと、認証リクエスト自体が失敗しますので、iOS8以降では必須となります 。

A005

ダイアログでユーザが選択した内容は、アプリの設定情報として記憶され、これをアプリ側から変更することは出来ません。

A006

(4) 情報更新開始

CLLocationManagerstartUpdatingLocationメソッドで、位置情報の更新が始まります。

[self.locationManager startUpdatingLocation];

(5) 位置情報の取得

位置情報は、CLLocationManagerのデリゲートメソッドで取得します。

ViewControllerをデリゲートにして、位置情報を受け取るには、まずは、ビューコントローラにCLLocationManagerDelegateを追加します。

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface ViewController : UIViewController<CLLocationManagerDelegate>

@end
self.locationManager.delegate = self;

続いて、didUpdateLocationsメソッドを実装します。

- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    // 位置情報を取り出す
    CLLocation *newLocation = [locations lastObject];
    //緯度
    double latitude = newLocation.coordinate.latitude;
   //経度
    double longitude = newLocation.coordinate.longitude;
    NSLog(@"%f",latitude);
    NSLog(@"%f",longitude);

}

上記のメソッドは、位置が変化した際に呼び出されます。(ただし、指定した更新期間に依存します)

// 更新間隔はdistanceFilterプロパティ
self.locationManager.distanceFilter = 500;

以上で、位置情報を取得するのために必要な最低限の実装は終わりです。 以降、付加的な機能の利用に関して、幾つか紹介させて頂きます。

3 認証状態の取得

認証の許可状況は、以下の6種類です。

  • kCLAuthorizationStatusNotDetermined(未設定)
  • kCLAuthorizationStatusRestricted(機能制限で利用が制限)
  • kCLAuthorizationStatusDenied(禁止)
  • kCLAuthorizationStatusAuthorized (許可) <=(deprecated)
  • kCLAuthorizationStatusAuthorizedAlways (常に許可)
  • kCLAuthorizationStatusAuthorizedWhenInUse (使用中のみ許可)

上から4つが、iOS7までのもので、5番目、6番目が、iOS8以降で新設されたものです。 なお、kCLAuthorizationStatusAuthorizedが、deprecatedになっており、これが置き換わったという事のようです。

認証のステータスが変化するたびに、次のdidChangeAuthorizationStatusデリゲートメソッドが呼び出されますので、ここでチェックが可能です。

-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    NSLog(@"statusは%D", status);

}

4 位置情報サービスの停止

startUpdatingLocationで開始したサービスは、 stopUpdatingLocationで停止できます。

[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;

 

5 iOS7対応

iOS 7 をサポートする場合は、NSLocationUsageDescriptionkCLAuthorizationStatusAuthorizedを使用する必要があります。

ただし、使用する場合にはメソッドが使用可能かどうかを確認する必要があります。

if self.locationManager.respondsToSelector("requestWhenInUseAuthorization") {
    self.locationManager.requestWhenInUseAuthorization()
}

6 シュミレータによる位置情報

シュミレータで実行している場合、Xcodeの矢印記号で、予めセットされている座標を模擬的に返す事が出来ます。

A008

また、GPXファイルを作成することで、任意の位置をシュミレートすることも出来ます。

GPXファイルとは、位置情報を扱うXML形式のファイルです。

たテキストファイルで、waypoint形式のサンプルは次のようなデータになっています。

<?xml version="1.0"?>
<gpx version="1.1" creator="drive.py coded by basuke">
    <wpt lat="35.681507" lon="139.765581">
        <name>Tokyo Station, 1 Chome-9 Marunouchi, Chiyoda, Tokyo, Japan</name>
    </wpt>
</gpx>

これをプロジェクトに追加すると、これを選択することが可能になります。

A010

A009

7 まとめ

今回は、位置情報取得に関してまとめてみました。

アプリから位置情報を取得するだけなら、これ以上考える必要はないのですが、 標準位置情報サービス (Standard Location Service)、 ビーコン領域の観測 (Beacon Region Monitoring)、 ビーコンの距離測定 (Ranging)などのCoreLocationサービスも、 それぞれ、必要なWhenInUse/Always認証がありますので、併用している場合は、注意が必要です。