iOS Tips #5 位置情報サービスのアクセス制限
iOSで位置情報サービスを利用するときのTipsです。普段iOS端末を利用されている方であれば一度は以下のようなダイアログを見たことがあるかと思います。
iOSではこの仕組みのおかげで、ユーザーが意図していないのに個人情報にアクセスしてしまうことを防いだり、悪意を持ったアプリから個人情報を守ってくれています。iOSで扱う個人情報は様々ですが、今回は位置情報サービスへのアクセス制限の実装方法を紹介したいと思います。
プロジェクトの作成
まずは、XcodeよりSingle View Applicationを選択し、以下の内容でプロジェクトを作成しましょう。
項目 | 設定値 |
---|---|
Product Name | LocationAccessSample |
Organization Name | 自分の名前(サンプルなのでテキトー) |
Company Identifier | 会社名(サンプルなのでテキトー) |
Class Prefix | なし |
Devices | iPhone |
Use Storyboards | チェックする(ストーリーボードを使用) |
Use Automatic Reference Counting | チェックする(ARC有効) |
Include Unit Tests | チェックしない(unit testのターゲットを含まない) |
CoreLocation.frameworkの追加
位置情報サービスを利用するにはCoreLocation.frameworkを使用するのでLocationAccessSampleプロジェクトにCoreLocation.frameworkを追加しましょう。
ViewControllerの実装
今回は位置情報サービスを利用するロジックをViewControllerに実装します。まずは以下のように実装してください。
ViewController.m
#import "ViewController.h" #import <CoreLocation/CoreLocation.h> @interface ViewController () <CLLocationManagerDelegate> @property (strong, nonatomic) CLLocationManager *locationManager; @end @implementation ViewController #pragma mark - UIViewController lifecicle event methods - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // 位置情報サービスへのアクセスを開始する [self startLocationService]; } #pragma mark - Private methods - (void)startLocationService { // このアプリの位置情報サービスへの認証状態を取得する CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; switch (status) { case kCLAuthorizationStatusAuthorized: // 位置情報サービスへのアクセスが許可されている case kCLAuthorizationStatusNotDetermined: // 位置情報サービスへのアクセスを許可するか選択されていない { // 位置情報サービスへのアクセスを許可するか確認するダイアログを表示する self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; [self.locationManager startUpdatingLocation]; } break; case kCLAuthorizationStatusRestricted: // 設定 > 一般 > 機能制限で利用が制限されている { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"設定 > 一般 > 機能制限で利用が制限されてるよ!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } break; case kCLAuthorizationStatusDenied: // ユーザーがこのアプリでの位置情報サービスへのアクセスを許可していない { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"このアプリでの位置情報サービスへのアクセスを許可されていないよ!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } break; default: break; } } - (void)stopLocationService { // 位置情報サービスを停止する [self.locationManager stopUpdatingLocation]; self.locationManager.delegate = nil; self.locationManager = nil; } #pragma mark - CLLocationManagerDelegate methods // 位置情報サービスへのアクセスが許可されていればこのデリゲートメソッドが定期的に実行される - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { NSLog(@"%@", locations); } // 位置情報サービスへのアクセスが失敗した場合にこのデリゲートメソッドが呼ばれる - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { switch (error.code) { case kCLErrorDenied: // 確認ダイアログで許可しないを選択した { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"このアプリでの位置情報サービスへのアクセスを許可されなかったよ!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } break; default: { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"位置情報の取得に失敗したよ!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } break; } } // 位置情報サービスの設定が変更された場合にこのデリゲートメソッドが呼ばれる - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { switch (status) { case kCLAuthorizationStatusRestricted: // 設定 > 一般 > 機能制限で利用が制限されている { // 位置情報サービスを停止する [self stopLocationService]; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"設定 > 一般 > 機能制限で利用が制限されてるよ!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } break; case kCLAuthorizationStatusDenied: // ユーザーがこのアプリでの位置情報サービスへのアクセスを許可していない { // 位置情報サービスを停止する [self stopLocationService]; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"このアプリでの位置情報サービスへのアクセスを許可されていないよ!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } break; default: break; } } @end
位置情報サービスへの認証状態を取得する
位置情報サービスの利用を開始するまえに、アプリが位置情報サービスへのアクセスが許可されているかを調べます。これにはCLLocationManagerクラスのクラスメソッド「+ (CLAuthorizationStatus)authorizationStatus(ViewController.m:32行目)」を使用します。このメソッドを実行するとCLAuthorizationStatusで定義される以下のステータスが返されます。
設定値 | 説明 |
---|---|
kCLAuthorizationStatusNotDetermined | アプリ起動後、位置情報サービスへのアクセスを許可するかまだ選択されていない状態 |
kCLAuthorizationStatusRestricted | 設定 > 一般 > 機能制限により位置情報サービスの利用が制限されている状態 |
kCLAuthorizationStatusDenied | ユーザーがこのアプリでの位置情報サービスへのアクセスを許可していない状態 |
kCLAuthorizationStatusAuthorized | ユーザーがこのアプリでの位置情報サービスへのアクセスを許可している状態 |
kCLAuthorizationStatusRestricted
ユーザーが機能制限(ペアレントコントロール)により意図的に位置情報サービスの利用を制限している場合にこのステータスが返されます。この場合、ユーザーによって機能制限を解除してもらわないと位置情報サービスを利用することができません。機能制限の設定は[設定 > 一般 > 機能制限]で行います。
kCLAuthorizationStatusDenied
ユーザーが意図的にこのアプリでの位置情報サービスへのアクセスを許可していない場合はこのステータスが返されます(ダイアログで「許可しない」を選択した場合など)。この設定は[設定 > プライバシー > 位置情報サービス]から行います。
位置情報サービスの利用を開始する
+ (CLAuthorizationStatus)authorizationStatusでkCLAuthorizationStatusNotDeterminedかkCLAuthorizationStatusAuthorizedが返された場合は位置情報サービスの利用開始を試みます(ViewController.m:39〜41行目)。ここが重要なのですが、CLLocationManagerクラスで定義されるメソッド「- (void)startUpdatingLocation」です。最初に説明したダイアログですが、実はこの「- (void)startUpdatingLocation」が初めて実行されるタイミングで表示されます。
位置情報サービスへのアクセスが許可された場合
正常に位置情報サービスの利用が開始できればこのアプリから位置情報サービスにアクセスすることができます(ViewController.m:85〜88行目)。
位置情報サービスへのアクセスが拒否された場合
ダイアログで「許可しない」が選択されると、デリゲートメソッド「- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error」が実行され、errorインスタンスのプロパティ変数codeにkCLErrorDenied」がセットされます。
iOS6以降:確認ダイアログに独自のメッセージを追加する
iOS6からはXxx-Info.plistにNSLocationUsageDescriptionを追加することで、確認ダイアログに独自のメッセージを追加することができます。
まとめ
iOSではこのようにプライバシーに関する機能が定義されています。次回は写真か連絡先について書きたいと思います。