On iOS, you need to properly request permissions from the user in order to access the camera roll. With iOS14, PHAccessLevel and PHAuthorizationStatus.limited have been added, and the behavior has become complicated, so this is a memorandum of investigation. This is a summary of PHAuthorizationStatus according to the status of "Allow access to photos" and what you can do.
Confirmation: iOS 13.4.1
"Allow access to photos" | authorizationStatus() | requestAuthorization() |
---|---|---|
unconfirmed | .notDetermined | ○ (displayed) |
reading/writing | .authorized | × (not displayed) |
not allowed | .denied | × |
Confirmation: iOS 14.2.1
"Allow access to photos" | authorizationStatus() | authorizationStatus (for: .addOnly) |
authorizationStatus (for: .readWrite) |
requestAuthorization (for: .addOnly) |
requestAuthorization (for: .readWrite) |
---|---|---|---|---|---|
unconfirmed | .notDetermined | .notDetermined | .notDetermined | ○ | ○ |
"Allow access to photos" | authorizationStatus() | authorizationStatus (for: .addOnly) |
authorizationStatus (for: .readWrite) |
requestAuthorization (for: .addOnly) |
requestAuthorization (for: .readWrite) |
---|---|---|---|---|---|
Add photo only (requestAuthorization(for: .addOnly)"OK") |
.notDetermined | .authorized | .notDetermined | × | ○ |
None (requestAuthorization(for: .addOnly)"Do not allow") |
.notDetermined | .denied | .notDetermined | × | ○ |
"Allow access to photos" | authorizationStatus() | authorizationStatus (for: .addOnly) |
authorizationStatus (for: .readWrite) |
requestAuthorization (for: .addOnly) |
requestAuthorization (for: .readWrite) |
---|---|---|---|---|---|
Selected photo (requestAuthorization(for: .readWrite)で「Selected photo」) |
.authorized | .limited | .limited | × | × |
All photos (requestAuthorization(for: .readWrite)"Allow access to all photos") |
.authorized | .authorized | .authorized | × | × |
None (requestAuthorization(for: .readWrite)"Do not allow") |
.denied | .notDetermined | .denied | ○ | × |
Reproduction procedure When only one of authorizationStatus (for: .addOnly) and authorizationStatus (for: .readWrite) is .notDetermined, requestAuthorization is performed with AccessLevel of .notDetermined.
State of setting screen
"Allow access to photos" | authorizationStatus() | authorizationStatus (for: .addOnly) |
authorizationStatus (for: .readWrite) |
---|---|---|---|
Add photo only | .denied | .authorized | .denied |
Selected photo | .authorized | . limited | . limited |
All photos | .authorized | .authorized | .authorized |
None | .denied | .denied | .denied |
Can be saved when ReadWrite AuthorizationStatus is .authorized
PHPhotoLibrary.authorizationStatus(for: .readWrite) == .authorized
Can be saved when the authorizationStatus of addOnly is .authorized or .limited
PHPhotoLibrary.authorizationStatus(for: . addOnly) == .authorized or . limited
class AuthorizationStatusChecker {
enum PhotoLibraryAuthorizationStatus {
case readWrite
case addOnly
case denied
}
static func checkPhotoLibrary(handler: @escaping (PhotoLibraryAuthorizationStatus) -> Void) {
let readWrite = PHPhotoLibrary.authorizationStatus(for: .readWrite)
let addOnly = PHPhotoLibrary.authorizationStatus(for: .addOnly)
switch (readWrite, addOnly) {
case (.authorized, _):
handler(.readWrite)
case (.notDetermined, _):
PHPhotoLibrary.requestAuthorization(for: .readWrite) { (_: PHAuthorizationStatus) in
Self.checkPhotoLibrary(handler: handler)
}
case (_, .authorized), (_, .limited):
handler(.addOnly)
case (_, .notDetermined):
PHPhotoLibrary.requestAuthorization(for: .addOnly) { (_: PHAuthorizationStatus) in
Self.checkPhotoLibrary(handler: handler)
}
default:
handler(.denied)
}
}
}
AuthorizationStatusChecker.checkPhotoLibrary { [weak self](status) in
switch status {
case .readWrite:
self?.saveToAlbum(name: "MyAlbum")
case .addOnly:
self?.saveToCameraRoll()
case .denied:
break
}
}