新しい写真選択PHPickerViewController
iOS14ではアルバムへのアクセス権限が見直されました。
従来のUIImagePickerを使用した写真選択を行っているアプリはiOS14においては、是非PHPickerViewControllerに置き換えを行いましょう。
PHPickerViewControllerを使うメリット
写真選択だけであれば、アプリに写真アクセス権限を与える必要がありません。
初回起動時のあの煩わしい権限選択ダイアログとサヨナラです。
これはPHPickerViewControllerが別プロセス(ホストアプリとは別)で動作するため、写真アクセスはPHPickerが行います。そこからapp extensionの仕組みを利用してホストアプリに選択した写真情報を渡すという仕組みをとるため、アルバムへのアクセス権限は不要になったということですね。
またPHPickerViewControllerは複数枚写真選択にも対応しています。
目的
写真を選択してそのままファイルを取得してバックエンドに送信を行いたい、またはアプリに保存したいケースを想定します。
loadObjectではUIImageとなるためオリジナルのメタ情報が失われてしまうと困る人を対象とします。
環境
Xcode12
iOS14
写真選択の表示
import PhotosUI
private func showPhpicker() {
//あとからPHAssetとして取得する場合は引数を指定。
var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
//同時写真選択数。0で無制限
config.selectionLimit = 1
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = self
self.present(pickerViewController, animated: true, completion: nil)
}
選択後の処理
以下のような感じでしょうか。
HEICは中に格納されているJPEGを抜き出しています。
画像の場合はloadDataRepresentationメソッドで取得します。
loadItemでURLを取得してそこからDataにする方法を考えつきましたが、あくまでもPHPickerViewContrllerのプロセス上だけでアルバムのアクセスが可能となっているので、いくらURLが分かったとしてもアプリからURL経由でアルバムのリソースへのアクセスは行なえません。
/// 選択後のメソッド
/// - Parameters:
/// - picker: PHPickerVIewController
/// - results: 選択結果のリスト
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: {
// TODO: PHPickerViewが閉じた後の処理
})
guard let provider = results.first?.itemProvider else { return }
guard let typeIdentifer = provider.registeredTypeIdentifiers.first else { return }
// 判定可能な識別子であるかチェック
if provider.hasItemConformingToTypeIdentifier(typeIdentifer) {
//Live Photoとして取得可能化
if provider.canLoadObject(ofClass: PHLivePhoto.self) {
//LivePhotoはClassを指定してLoadObjectで読み込み
provider.loadObject(ofClass: PHLivePhoto.self) { (livePhotoObject, error) in
do {
if let livePhoto:PHLivePhoto = livePhotoObject as? PHLivePhoto {
// Live Photoのプロパティから静止画を抜き出す(HEIC形式)
if let imageUrl = livePhoto.value(forKey: "imageURL") as? URL {
// URLからDataを生成(HEIC内のデータを参照してるため取得できる
let data:Data = try Data(contentsOf: imageUrl)
//パスを生成して画像を保存する
//data.write(to: URL)
}
}
} catch {
}
}
} else if provider.canLoadObject(ofClass: UIImage.self) {
//一般的な画像
// 画像の場合はloadObjectでUIImageまたはloadDataで取得する。
// loadItemでURLを取得する場合、URLからUIImageまたはDataの取得はアルバムへのアクセス権限が必要になる。
provider.loadDataRepresentation(forTypeIdentifier: typeIdentifer) { (data, error) in
if let imageData = data {
var ext = ""
switch typeIdentifer{
case "public.jpeg":
ext = ".jpg"
case "public.png":
ext = ".png"
default:
break
}
//画像の保存
//data?.write(to: URL)
}
}
}
}
}
サンプルプロジェクトは以下です。
https://github.com/onizine/PHPickerGetDataSample