[iOS]近年の写真/動画とプライバシー
iOS 13〜iOS 17までの、写真/動画とプライバシーについて時系列で書いておきます。
※この記事ではiOSかつ本体(App ClipsやWidgetではない)におけるプライバシーについての記事です。
〜iOS 13
写真/動画にアクセスする場合、次のようなコードを書いて、ステータスチェック、権限の要求をしていた。
if PHPhotoLibrary.authorizationStatus() == .notDetermined {
PHPhotoLibrary.requestAuthorization { (status) in
// hogehgoe...
}
}
同時に、Info.plistにも許諾メッセージの設定をする必要がある。 NSPhotoLibraryAddUsageDescription
はwrite-only、 NSPhotoLibraryUsageDescription
はread or writeな権限のときに使う。
<key>NSPhotoLibraryAddUsageDescription</key>
<string>写真を保存するためにアクセス権が必要です。</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>写真を表示するためにアクセス権が必要です。</string>
iOS 14
※写真以外のことも含めた、WWDC20においてのプライバシーの変更点についてはかつて記事にしているので興味ある方はこちらもどうぞ。
→WWDC2020での許諾周りのアップデートまとめ。
PHPickerViewControllerの登場
PHPickerViewController
が登場した。写真ピッカーを表示する時に直接Photos Libraryにアクセスを要求する必要がないので許諾ダイアログを出す必要がなく、この方法が推奨されている。
詳しくはかつて記事にしたこちらをどうぞ。
→UIImagePickerControllerに代わるPHPickerViewControllerの紹介
※iOS 16でPHPickerFilterの種類が増え、スクリーンショットやスローモーション動画などをフィルタリングできるようになっている。複合フィルタも .all(of:)
, .not(_:)
が登場した。一部はiOS 16 SDKでコンパイルしているなら、iOS 15でも使用できる。
「写真を選択...」
PHAuthorizationStatus
に .limited
が増えた。ユーザが選択した写真しかアプリからアクセスできない状態を作ることができる。
これとは別に、 PHAccessLevel
というアクセスレベルを指定するenumが登場している。 .addOnly
(書き込みのみ)を指定した場合は左、 .readWrite
(読み書き)を指定した場合は右の許諾ダイアログになる。
関連して、 PHPhotoLibrary.authorizationStatus()
(ステータス確認API)に更新が入り、アクセスレベルの指定が必要になっている。 .readWrite
レベルにおけるステータス確認は以下の通り。
許諾リクエスト処理に関してもアクセスレベルの指定が必要になっている。
もしユーザが「写真を選択...」を選択した場合、何も対策をしないとアプリのライフサイクルごと、PhotoKitのコンテンツにアクセスする度に現在のアクセス権限を維持するか、変更するかを問うアラートが出てきてしまう。
許諾アラートを毎回表示させないためには、Info.plistの PHPhotoLibraryPreventAutomaticLimitedAccessAlert
にYESを設定すれば良い。
iOS 16
PHPickerViewController
はSwiftUIから直接使うことはできない問題があった。iOS 16から登場した PhotosPicker
はSwiftUIから直接使うことができる。こちらも許諾ダイアログを出す必要がない。
使い方は簡単で、例えば複数の写真を選択するピッカーは以下のコードで実現できる。 selectedPhotos
に選択した写真が入ってくる。
struct ContentView: View {
@State private var selectedPhotos: [PhotosPickerItem] = []
// 単一選択にしたい場合はこちらを使用する
//@State private var selectedPhoto: PhotosPickerItem? = nil
var body: some View {
PhotosPicker(selection: $selectedPhotos,
matching: .images) {
Text("show PhotosPicker")
}
}
}
Discussion