In ios 11 we now have "Add photos only" permission setting.
But how we now determinate which photo library access level is set?
[PHPhotoLibrary authorizationStatus] works only for "Read and Write" permission check. If app asked only for "Add photos only" permission then it stays PHAuthorizationStatusNotDetermined. If user changed it from "Read and Write" to "Add photos only" it gives PHAuthorizationStatusDenied.
So, how can I tell if my app have permissions to do "Export to Camera Roll" feature, which dosen't require read permissions?
since iOS 11, in order to gain only Write access you'll need to add the NSPhotoLibraryAddUsageDescription in your info.plist.
The problem here arises if you want to check if the user allows you to do that. It cannot be done through the [PHPhotoLibrary authorizationStatus] method, since that calls out the read/write popup (and you'll need to have NSPhotoLibraryUsageDescription in your info.plist too).
If you want to check if the user gave your app access to write, you'll have to call UIImageWriteToSavedPhotosAlbum (which I'm guessing you already call if you want to add data to the gallery), and that gives you a callback which tells you if the saving worked or not, but the bigger thing is that it shows the user your NSPhotoLibraryAddUsageDescription text.
Now, in order to make sure you have access on both, you should add both NSPhotoLibraryAddUsageDescription and NSPhotoLibraryUsageDescription added to your info.plist and do your regular check with the PHPhotoLibrary, and if that fails, then you can only check when you want to save the data to the library with UIImageWriteToSavedPhotosAlbum.
I'd say you can check only with UIImageWriteToSavedPhotosAlbum but you need to actually save an image to the user gallery to do that and it's hacky, which is a no no.
Since iOS 14 you are able to check if the user gave permission for add photos only:
PHPhotoLibrary.authorizationStatus(for: .addOnly)
Unfortunately that means below iOS 14 you don't know if the user has selected the add photos only or another option. The only other way to check is to actually use UIImageWriteToSavedPhotosAlbum like mikebld said in his answer.
Related
When opening images using presentPreviewAnimated: share menu contains "Save Image" option. It works fine if user gave access to photos before (and if user explicitly disabled access there's no such option at all), but otherwise app crashes. I can check permission before opening file, but it would be wrong if the user doesn't need to save it.
How can I check if user wants to save image and permission request is needed?
Solved by adding NSPhotoLibraryAddUsageDescription to plist, thanks to this post.
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: { })
}
Even if I set access to Photos in Settings to "Never" with above code I can still present image picker and show photos. I'll check for PHPhotoLibrary.authorizationStatus() before showing it, but I would like to know is this expected behaviour?
Okay, you can sort of piece this together from answers and comments already, but to try to tell a more complete story...
In iOS 11, UIImagePickerController runs as a separate process from your app. That means:
Your app can't see the user's whole Photos library — it gets read-only access just for whichever asset(s) the user chooses in the image picker.
Because of (1), your app doesn't need the standard privacy authorization for Photos library access. The user explicitly chooses a specific asset (or multiple) for use in your app, which means the user is granting your app permission to read the asset(s) in question.
You can see more about this in the WWDC17 talk on PhotoKit.
(By the way, this model matches what you've seen in the Contacts framework since iOS 9; if you show contact picker, your app only gets a one-time drop of contact information for the contact(s) the user picked, not ongoing read/write access to the Contacts database, so the contact picker doesn't require special privacy permission.)
PHPhotoLibrary and its authorization status reflect the global read/write permission for Photos access that users can control from Settings > Privacy. (That's the one where your Info.plist needs NSPhotoLibraryUsageDescription.) Any use of the PHPhotoLibrary API requires this permission, regardless of whether your app's use of that API is only for writing or only for reading. This has been true since PhotoKit was introduced in iOS 8.
If you're not using PHPhotoLibrary, PHAsset, etc, there are narrower permission options that are new in iOS 11 (and not part of the Photos.framework API):
As noted above, UIImagePickerController doesn't need blanket Privacy Settings permission because each use grants one-time read access for the specific assets chosen.
If you need only to add new assets to the Photos library, use UIImageWriteToSavedPhotosAlbum or UISaveVideoAtPathToSavedPhotosAlbum. With those you can put NSPhotoLibraryAddUsageDescription in your Info.plist — then the system's Privacy Settings will make clear to the user that they're not giving your permission to see or modify existing assets, only to add new ones.
If the user grants add-only permission, it applies only to those UIKit functions — attempting to use PHPhotoLibrary will still prompt for (and require the Info.plist key for) read/write access.
See this part of the WWDC17 talk for more on the add-only privacy setting.
Is this expected behaviour? - YES.
From the docs - https://developer.apple.com/documentation/uikit/uiimagepickercontroller/1619144-issourcetypeavailable
true if the device supports the specified source type; false if the specified source type is not available.
It tells you if the device supports the source type and not if the app has the permission to access it.
As you already mentioned in the question, PHPhotoLibrary.authorizationStatus() would be correct way to check this.
This (new) behaviour does sound logical to me, here's why. When using UIImagePickerController your app doesn't actually get access to any photos. It only sees the one your user has picked, when that happens; and if the user taps Cancel in the picker none of those become available to the app.
PHPhotoLibrary is part of a separate framework, Photos, where you can do a lot of stuff with the user's photo library, and therefore need permission.
So if you are only using UIImagePickerController I'd suggest not mixing Photos stuff in.
Disclaimer: haven't heard of any official statement from Apple folks. This forum thread looks relevant, maybe we get a reply there. UPD: there it is, same idea.
Also, if you're evil enough you can theoretically fiddle with UIImagePickerController view hierarchy at runtime and examine whatever the user sees there. But that's again for Apple to deal with, we should just be nice :-)
UIImagePickerController and PHPhotoLibrary responsible for different areas.
You should check both: auth status and source availability.
PHAuthorizationStatus
Information about your app’s authorization to access the user’s Photos
library.
isSourceTypeAvailable
Discussion
Because a media source may not be present or may be unavailable,
devices may not always support all source types.
For example, if you
attempt to pick an image from the user’s library and the library is
empty, this method returns false. Similarly, if the camera is already
in use, this method returns false.
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: { })
}
Even if I set access to Photos in Settings to "Never" with above code I can still present image picker and show photos. I'll check for PHPhotoLibrary.authorizationStatus() before showing it, but I would like to know is this expected behaviour?
Okay, you can sort of piece this together from answers and comments already, but to try to tell a more complete story...
In iOS 11, UIImagePickerController runs as a separate process from your app. That means:
Your app can't see the user's whole Photos library — it gets read-only access just for whichever asset(s) the user chooses in the image picker.
Because of (1), your app doesn't need the standard privacy authorization for Photos library access. The user explicitly chooses a specific asset (or multiple) for use in your app, which means the user is granting your app permission to read the asset(s) in question.
You can see more about this in the WWDC17 talk on PhotoKit.
(By the way, this model matches what you've seen in the Contacts framework since iOS 9; if you show contact picker, your app only gets a one-time drop of contact information for the contact(s) the user picked, not ongoing read/write access to the Contacts database, so the contact picker doesn't require special privacy permission.)
PHPhotoLibrary and its authorization status reflect the global read/write permission for Photos access that users can control from Settings > Privacy. (That's the one where your Info.plist needs NSPhotoLibraryUsageDescription.) Any use of the PHPhotoLibrary API requires this permission, regardless of whether your app's use of that API is only for writing or only for reading. This has been true since PhotoKit was introduced in iOS 8.
If you're not using PHPhotoLibrary, PHAsset, etc, there are narrower permission options that are new in iOS 11 (and not part of the Photos.framework API):
As noted above, UIImagePickerController doesn't need blanket Privacy Settings permission because each use grants one-time read access for the specific assets chosen.
If you need only to add new assets to the Photos library, use UIImageWriteToSavedPhotosAlbum or UISaveVideoAtPathToSavedPhotosAlbum. With those you can put NSPhotoLibraryAddUsageDescription in your Info.plist — then the system's Privacy Settings will make clear to the user that they're not giving your permission to see or modify existing assets, only to add new ones.
If the user grants add-only permission, it applies only to those UIKit functions — attempting to use PHPhotoLibrary will still prompt for (and require the Info.plist key for) read/write access.
See this part of the WWDC17 talk for more on the add-only privacy setting.
Is this expected behaviour? - YES.
From the docs - https://developer.apple.com/documentation/uikit/uiimagepickercontroller/1619144-issourcetypeavailable
true if the device supports the specified source type; false if the specified source type is not available.
It tells you if the device supports the source type and not if the app has the permission to access it.
As you already mentioned in the question, PHPhotoLibrary.authorizationStatus() would be correct way to check this.
This (new) behaviour does sound logical to me, here's why. When using UIImagePickerController your app doesn't actually get access to any photos. It only sees the one your user has picked, when that happens; and if the user taps Cancel in the picker none of those become available to the app.
PHPhotoLibrary is part of a separate framework, Photos, where you can do a lot of stuff with the user's photo library, and therefore need permission.
So if you are only using UIImagePickerController I'd suggest not mixing Photos stuff in.
Disclaimer: haven't heard of any official statement from Apple folks. This forum thread looks relevant, maybe we get a reply there. UPD: there it is, same idea.
Also, if you're evil enough you can theoretically fiddle with UIImagePickerController view hierarchy at runtime and examine whatever the user sees there. But that's again for Apple to deal with, we should just be nice :-)
UIImagePickerController and PHPhotoLibrary responsible for different areas.
You should check both: auth status and source availability.
PHAuthorizationStatus
Information about your app’s authorization to access the user’s Photos
library.
isSourceTypeAvailable
Discussion
Because a media source may not be present or may be unavailable,
devices may not always support all source types.
For example, if you
attempt to pick an image from the user’s library and the library is
empty, this method returns false. Similarly, if the camera is already
in use, this method returns false.
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: { })
}
Even if I set access to Photos in Settings to "Never" with above code I can still present image picker and show photos. I'll check for PHPhotoLibrary.authorizationStatus() before showing it, but I would like to know is this expected behaviour?
Okay, you can sort of piece this together from answers and comments already, but to try to tell a more complete story...
In iOS 11, UIImagePickerController runs as a separate process from your app. That means:
Your app can't see the user's whole Photos library — it gets read-only access just for whichever asset(s) the user chooses in the image picker.
Because of (1), your app doesn't need the standard privacy authorization for Photos library access. The user explicitly chooses a specific asset (or multiple) for use in your app, which means the user is granting your app permission to read the asset(s) in question.
You can see more about this in the WWDC17 talk on PhotoKit.
(By the way, this model matches what you've seen in the Contacts framework since iOS 9; if you show contact picker, your app only gets a one-time drop of contact information for the contact(s) the user picked, not ongoing read/write access to the Contacts database, so the contact picker doesn't require special privacy permission.)
PHPhotoLibrary and its authorization status reflect the global read/write permission for Photos access that users can control from Settings > Privacy. (That's the one where your Info.plist needs NSPhotoLibraryUsageDescription.) Any use of the PHPhotoLibrary API requires this permission, regardless of whether your app's use of that API is only for writing or only for reading. This has been true since PhotoKit was introduced in iOS 8.
If you're not using PHPhotoLibrary, PHAsset, etc, there are narrower permission options that are new in iOS 11 (and not part of the Photos.framework API):
As noted above, UIImagePickerController doesn't need blanket Privacy Settings permission because each use grants one-time read access for the specific assets chosen.
If you need only to add new assets to the Photos library, use UIImageWriteToSavedPhotosAlbum or UISaveVideoAtPathToSavedPhotosAlbum. With those you can put NSPhotoLibraryAddUsageDescription in your Info.plist — then the system's Privacy Settings will make clear to the user that they're not giving your permission to see or modify existing assets, only to add new ones.
If the user grants add-only permission, it applies only to those UIKit functions — attempting to use PHPhotoLibrary will still prompt for (and require the Info.plist key for) read/write access.
See this part of the WWDC17 talk for more on the add-only privacy setting.
Is this expected behaviour? - YES.
From the docs - https://developer.apple.com/documentation/uikit/uiimagepickercontroller/1619144-issourcetypeavailable
true if the device supports the specified source type; false if the specified source type is not available.
It tells you if the device supports the source type and not if the app has the permission to access it.
As you already mentioned in the question, PHPhotoLibrary.authorizationStatus() would be correct way to check this.
This (new) behaviour does sound logical to me, here's why. When using UIImagePickerController your app doesn't actually get access to any photos. It only sees the one your user has picked, when that happens; and if the user taps Cancel in the picker none of those become available to the app.
PHPhotoLibrary is part of a separate framework, Photos, where you can do a lot of stuff with the user's photo library, and therefore need permission.
So if you are only using UIImagePickerController I'd suggest not mixing Photos stuff in.
Disclaimer: haven't heard of any official statement from Apple folks. This forum thread looks relevant, maybe we get a reply there. UPD: there it is, same idea.
Also, if you're evil enough you can theoretically fiddle with UIImagePickerController view hierarchy at runtime and examine whatever the user sees there. But that's again for Apple to deal with, we should just be nice :-)
UIImagePickerController and PHPhotoLibrary responsible for different areas.
You should check both: auth status and source availability.
PHAuthorizationStatus
Information about your app’s authorization to access the user’s Photos
library.
isSourceTypeAvailable
Discussion
Because a media source may not be present or may be unavailable,
devices may not always support all source types.
For example, if you
attempt to pick an image from the user’s library and the library is
empty, this method returns false. Similarly, if the camera is already
in use, this method returns false.
When the app is first run it asks for permission to access the photos!
What's the reason for that?
One way is run the code one line by one line or Another way is revert code to previous version.
And find from which version, the app become to ask permission at first launch.
Previously, when we enter select photo screen, we would write code to ask the permission.
I also try to add symbolic breakpoints like:
-[UIAlertView initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:]
And even find a class dump UIAlertView header in order to add symbolic breakpoint but not work. Add UIAlertController breakpoint also does not work.
The simulator OS is 8.3. And each time I must reset contents and setting to reproduce the issue.
Any hint or good idea will be appreciated!
Finally, I find out the following code cause the iOS system to pop up the "Allow our App to access their photo gallery" dialog. Thanks for Vijay's answer.
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
Starting with iOS 6, Apple now requires apps to get explicit user permission before accessing Contacts, Calendars, Reminders, and Photos. From the "Data Privacy" section in Apple's iOS 6 Release Notes:
In addition to location data, the system now asks the user’s permission before allowing third-party apps to access certain user data, including:
Contacts
Calendars
Reminders
Photo Library
For contact, calendar, and reminder data, your app needs to be prepared to be denied access to these items and to adjust its behavior accordingly. If the user has not yet been prompted to allow access, the returned structure is valid but contains no records. If the user has denied access, the app receives a NULL value or no data. If the user grants permission to the app, the system subsequently notifies the app that it needs to reload or revert the data.