iOS Tips #6 写真のアクセス制限

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

前回のiOS Tips #5 位置情報サービスのアクセス制限に引き続き、今回はiOSで写真へのアクセス制限の実装方法を紹介したいと思います。位置情報サービスと同様、アプリから写真にアクセスする場合の挙動を理解することで、安心して使ってもらえるアプリを構築することができます。

ios-tips-6_1

では早速サンプルを作ってみましょう。今回は以下の環境を前提に説明します。

Mac OS X 10.8 Moutain lion
Xcode 4.6.2
iOS SDK 6.1
iPhone 5

プロジェクトの作成

まずは、XcodeよりSingle View Applicationを選択し、以下の内容でプロジェクトを作成しましょう。

項目 設定値
Product Name PhotoAccessSample
Organization Name 自分の名前(サンプルなのでテキトー)
Company Identifier 会社名(サンプルなのでテキトー)
Class Prefix なし
Devices iPhone
Use Storyboards チェックする(ストーリーボードを使用)
Use Automatic Reference Counting チェックする(ARC有効)
Include Unit Tests チェックしない(unit testのターゲットを含まない)

AssetLibrary.frameworkの追加

写真へのアクセス制限を実装するのにAssetLibrary.frameworkを使用するのでPhotoAccessSampleプロジェクトにAssetLibrary.frameworkを追加しましょう。

ios-tips-6_2

ViewControllerの実装

今回は写真を利用するロジックをViewControllerに実装します。まずは以下のように実装してください。

ViewController.m
#import "ViewController.h"
#import <AssetsLibrary/AssetsLibrary.h>

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - UIViewController lifecicle event methods

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    
    // 写真へのアクセスを開始する
    [self startUsePicture];
}

#pragma mark - Private methods

- (void)startUsePicture
{
    // このアプリの写真への認証状態を取得する
    ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
    
    switch (status) {
        case ALAuthorizationStatusAuthorized: // 写真へのアクセスが許可されている
        case ALAuthorizationStatusNotDetermined: // 写真へのアクセスを許可するか選択されていない
        {
            __block NSMutableArray *groups = [NSMutableArray array];
            
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
            [library enumerateGroupsWithTypes:ALAssetsGroupAll
                                   usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                                       if (group) {
                                           // グループ名を配列に追加
                                           [groups addObject:[group valueForProperty:ALAssetsGroupPropertyName]];
                                       } else {
                                           // 端末のアルバム名を一覧に表示する
                                           dispatch_async(dispatch_get_main_queue(), ^{
                                               UIAlertView *alertView = [[UIAlertView alloc]
                                                                         initWithTitle:@"確認"
                                                                         message:[NSString stringWithFormat:
                                                                                  @"この端末のアルバム\n%@",
                                                                                  [groups componentsJoinedByString:@"\n"]]
                                                                         delegate:nil
                                                                         cancelButtonTitle:@"OK"
                                                                         otherButtonTitles:nil];
                                               
                                               [alertView show];
                                           });
                                       }
                                       
                                   } failureBlock:^(NSError *error) {
                                       dispatch_async(dispatch_get_main_queue(), ^{
                                           UIAlertView *alertView = [[UIAlertView alloc]
                                                                     initWithTitle:@"エラー"
                                                                     message:@"このアプリでの写真へのアクセスを許可されなかったよ!"
                                                                     delegate:nil
                                                                     cancelButtonTitle:@"OK"
                                                                     otherButtonTitles:nil];
                                           [alertView show];
                                       });
                                   }];
        }
            break;
            
        case ALAuthorizationStatusRestricted: // 設定 > 一般 > 機能制限で利用が制限されている
        {
            UIAlertView *alertView = [[UIAlertView alloc]
                                      initWithTitle:@"エラー"
                                      message:@"設定 > 一般 > 機能制限で利用が制限されてるよ!"
                                      delegate:nil
                                      cancelButtonTitle:@"OK"
                                      otherButtonTitles:nil];
            [alertView show];
        }
            break;
            
        case ALAuthorizationStatusDenied: // 設定 > プライバシー > 写真で利用が制限されている
        {
            UIAlertView *alertView = [[UIAlertView alloc]
                                      initWithTitle:@"エラー"
                                      message:@"設定 > プライバシー > 写真で利用が制限されてるよ!"
                                      delegate:nil
                                      cancelButtonTitle:@"OK"
                                      otherButtonTitles:nil];
            [alertView show];
        }
            break;
            
        default:
            break;
    }
}

@end

写真への認証状態を取得する

写真の利用を開始するまえに、アプリが写真へのアクセスが許可されているかを調べます。これにはALAssetsLibraryクラスのクラスメソッド「+ (ALAuthorizationStatus)authorizationStatus(ViewController.m:30行目)」を使用します。このメソッドを実行するとALAuthorizationStatusで定義される以下のステータスが返されます。

設定値 説明
ALAuthorizationStatusNotDetermined アプリ起動後、写真へのアクセスを許可するかまだ選択されていない状態
ALAuthorizationStatusRestricted 設定 > 一般 > 機能制限により写真の利用が制限されている状態
ALAuthorizationStatusDenied ユーザーがこのアプリでの写真へのアクセスを許可していない状態
ALAuthorizationStatusAuthorized ユーザーがこのアプリでの写真へのアクセスを許可している状態

名前が違うだけで位置情報サービスと同じような内容ですね。

ALAuthorizationStatusRestricted

ユーザーが機能制限(ペアレントコントロール)により意図的に写真の利用を制限している場合にこのステータスが返されます。この場合、ユーザーによって機能制限を解除してもらわないと写真を利用することができません。機能制限の設定は[設定 > 一般 > 機能制限]で行います。

ios-tips-6_5

ALAuthorizationStatusDenied

ユーザーが意図的にこのアプリでの写真へのアクセスを許可していない場合はこのステータスが返されます(ダイアログで「許可しない」を選択した場合など)。この設定は[設定 > プライバシー > 写真]から行います。

ios-tips-6_4

写真の利用を開始する

+ (ALAuthorizationStatus)authorizationStatusでALAuthorizationStatusNotDeterminedALAuthorizationStatusAuthorizedが返された場合は写真の利用開始を試みます(ViewController.m:38〜70行目)。ここが重要なのですが、ALAssetsLibraryクラスで定義されるメソッド「- (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock」です(なっが)。最初に説明したダイアログですが、実はこのメソッドが初めて実行されるタイミングで表示されます。これも位置情報サービスと同様ですね。

写真へのアクセスが許可されると、enumerationBlockで設定した処理が実行されます。ダイアログで「許可しない」が選択されると、failureBlockが実行されます。

iOS6以降:確認ダイアログに独自のメッセージを追加する

iOS6からはXxx-Info.plistにNSPhotoLibraryUsageDescriptionを追加することで、確認ダイアログに独自のメッセージを追加することができます。

ios-tips-6_3

ios-tips-6_6

UIImagePickerControllerを使用する場合

UIImagePickerControllerを使うはenumerationBlockの処理を以下のように変更するだけでOKです。

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
                       usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
						  UIImagePickerController *picker = [[UIImagePickerController alloc] init];
						  picker.delegate = self;
						  [self presentViewController:picker animated:YES completion:nil];
                       } failureBlock:^(NSError *error) {
                           ・・・
                       }];

まとめ

如何でしょうか?位置情報サービスを利用するときと基本的には変わらないですね! 次回は連絡先について書きたいと思います。