iOS 11 での UIImagePickerController の変更点
iOS 10 までは UIImagePickerController
と UIImagePickerControllerSourceTypePhotoLibrary
の組み合わせでフォトライブラリを表示する際にアクセス権限の確認を自動で行ってくれていた。
アクセス権限がなければ鍵マークが表示され一切の情報を取得する事ができない。ユーザの操作としては必ずキャンセルが行われる。*1
iOS 10
自動でアクセス許可のアラートが表示される
権限なしの状態ではキャンセルしか出来ない
権限があればフォトライブラリを表示、写真を選択可能
iOS 11 ではアクセス権限の確認が自動で行われない様になった。そして権限がなくともフォトライブラリの表示は行われ、写真の選択も出来てしまう。
iOS 11
権限の確認無しにいきなりフォトライブラリが表示
何が起こるか
写真の選択を行うと通常通り delegate メソッドが呼ばれる。
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
この時 info には
UIImagePickerControllerMediaType
UIImagePickerControllerOriginalImage
UIImagePickerControllerReferenceURL
UIImagePickerControllerImageURL
といった情報が入っている。
UIImagePickerControllerReferenceURL
には ALAsset
のURLが入っている。
iOS 11 で deprecated になったがまだ使う事は出来る。
ex.) assets-library://asset/asset.HEIC?id=97F34D03-1230-4F4E-9AA6-E7A7469158DE&ext=HEIC
フォトライブラリへのアクセスが許可されていれば以下の様にしてアセットへアクセスする事が出来る。
NSURL *assetURL = info[UIImagePickerControllerReferenceURL]; PHFetchResult<PHAsset *> *result = [PHAsset fetchAssetsWithALAssetURLs:@[assetURL] options:nil]; PHAsset *asset = result.firstObject; NSLog(@"%@ %@", result, asset);
ただし、iOS 11 の場合でアクセス権限無しでフォトライブラリを表示選択してこのコードが実行された場合 PHFetchResult
は PHUnauthorizedFetchResult
という Private クラスが返され、アセットの取得が出来ない。
アセットの取得には失敗するがアセットにアクセスしようとした事がトリガーとなってアクセス許可のアラートが表示される。
このタイミングのアラートでアクセス権限を得たとしても既にアセットのフェッチには失敗しているので、再度フォトライブラリを開くか assetURL を使って再度アセットをフェッチするなどしないとアセットは取得出来ない。
iOS 11 に対応する処理の流れとしては UIImagePickerController
を表示する前かアセットをフェッチする前に PHPhotoLibrary
の
+ (void)requestAuthorization:(void(^)(PHAuthorizationStatus status))handler;
で権限を得ておく必要がある。
iOS 10 まではそもそもアクセスが許可されていないとフォトライブラリが表示されないので、こういった事は問題は起こり得ない。
アクセス権限無しでフォトライブラリを開ける意味
アクセス権限が無い状態でも UIImagePickerControllerOriginalImage
で取得した UIImage
は利用する事が出来る。
また UIImagePickerControllerImageURL
を使って NSURL
から UIImage
や NSData
を作ったりファイルコピーなどする事も出来る。
UIImagePickerControllerImageURL
は iOS 11 で登場したもので元画像のファイルURLが入っている。
ex.) file:///private/var/mobile/Containers/Data/Application/1770CD90-C268-48BF-8A35-6210698472EF/tmp/EBD7BD90-2A50-4BEB-86D3-63ADB1E12CB0.jpeg
先の例だとアクセス権限が無い状態 = 未確認、つまり PHAuthorizationStatusNotDetermined
でのケースだったが、アクセス許可のアラートでアクセスが拒否された場合、つまり PHAuthorizationStatusDenied
の状態でも UIImagePickerController
によってフォトライブラリを開く事が出来る。
画像に様に許可アラートや設定画面でアクセスが許可されていなくてもフォトライブラリの表示と利用が可能
まとめ
- iOS 11 では
UIImagePickerController
によるフォトライブラリの表示はユーザのアクセス権限が不要になった。 - アクセス権限が明確に拒否 (Denied) されている場合でも
UIImagePickerController
経由で得られるUIImage
や画像のNSURL
を使ってユーザが選択した画像データを取り扱う事が出来る。 - フォトライブラリへのアクセスが発生する
PHAsset
の取得はアクセス権限が必要。
UIImagePickerController
での写真の表示と選択はユーザ操作によるものなのでOK(許可されていると同義)、PHAsset
の取得などアプリがコードでフォトライブラリへアクセスする場合はユーザには何をしているか見えないのでアクセス権限が必要という方針なんだろうと推察される。
※動作確認 iOS 11.0 Xcode 9
追記
WWDC 2017 - Session 702 Privacy and Your Apps
https://developer.apple.com/videos/play/wwdc2017/702/
Image picker without prompting for access
12:25 あたりから上記について写真ライブラリの書き込みのみパーミッションが必要な様に変更されたと言及有り。
WWDC 2017 - Session 505 What's New in Photos APIs
https://developer.apple.com/videos/play/wwdc2017/505/
2:15 からもこの仕様変更について詳しく言及あり。
*1:Info.plist に NSPhotoLibraryUsageDescription は記載済みの前提