Swift Photo Library Access

Accessing the camera and photo library in swift 4

Here is the code to load image from photos & camera in iOS.

⁃ You need to create an outlet of your UIImageView

⁃ Then add a tap gesture on to image view

⁃ Then connect tap gesture with the didTapOnImageView function.

⁃ Then add the following extension to your view controller.

//MARK:- Image Picker
extension YourViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

//This is the tap gesture added on my UIImageView.
@IBAction func didTapOnImageView(sender: UITapGestureRecognizer) {
//call Alert function
self.showAlert()
}

//Show alert to selected the media source type.
private func showAlert() {

let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .camera)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .photoLibrary)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
}

//get image from source type
private func getImage(fromSourceType sourceType: UIImagePickerController.SourceType) {

//Check is source type available
if UIImagePickerController.isSourceTypeAvailable(sourceType) {

let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = sourceType
self.present(imagePickerController, animated: true, completion: nil)
}
}

//MARK:- UIImagePickerViewDelegate.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

self.dismiss(animated: true) { [weak self] in

guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
//Setting image to your image view
self?.profileImgView.image = image
}
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}

}

Note: Don't forget to add the privacy settings in info.plist

Privacy - Camera Usage Description

Privacy - Photo Library Usage Description

I can access iOS Photo Library without requesting permission

As per UIImagePickerController behaviour, It never gives dialogue to the user for Photos access. UIImagePickerController only ask for the Camera permission.

You have to ask for Photos permission manually to the user. By using the below code you can ask the user for Photos permission.

import Photos

@IBAction func allowAccessToPhotos(_ sender: Any) {

let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a Source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .photoLibrary
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthorizationStatus {
case .authorized:
self.present(imagePickerController, animated: true, completion: nil)
case .notDetermined:
PHPhotoLibrary.requestAuthorization({
(newStatus) in
DispatchQueue.main.async {
if newStatus == PHAuthorizationStatus.authorized {
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("User denied")
}
}})
break
case .restricted:
print("restricted")
break
case .denied:
print("denied")
break
}}))

actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
}

Please refer reference.

Important Note:

If you're not asking for Photos permission to the user then It will cause rejection by the apple team. It depends on your luck, Sometimes the apple team ignore it and sometimes reject our app.

Swift Ask for user’s permission to access the photo library

i just add the key NSPhotoLibraryUsageDescription in Project/info/Custom IOS Target Properties . instead of info.plist and now it's working fine

Request Permission for Camera and Library in iOS 10 - Info.plist

You have to add the below permission in Info.plist. More Referance

Camera :

Key       :  Privacy - Camera Usage Description   
Value : $(PRODUCT_NAME) camera use

Photo :

Key       :  Privacy - Photo Library Usage Description    
Value : $(PRODUCT_NAME) photo use

Determine if the access to photo library is set or not - PHPhotoLibrary

Check +[PHPhotoLibrary authorizationStatus] – if not set, it will return PHAuthorizationStatusNotDetermined. (You can then request access using +requestAuthorization: on the same class.)

Swift Photo Library Access

It is not so simple but as mentioned by Rob you can save the photo asset url and later fetch it using the Photos framework. You can fetch them using PHImageManager method requestImageData.

import UIKit
import Photos
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@IBOutlet weak var imageView: UIImageView!
let galleryPicker = UIImagePickerController()
// create a method to fetch your photo asset and return an UIImage on completion
override func viewDidLoad() {
super.viewDidLoad()
// lets add a selector to when the user taps the image
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(openPicker)))
// request authorization
switch PHPhotoLibrary.authorizationStatus() {
case .authorized:
print("The user has explicitly granted your app access to the photo library.")
return
case .denied:
print("The user has explicitly denied your app access to the photo library.")
case .notDetermined:
PHPhotoLibrary.requestAuthorization { status in
print("status", status)
}
case .restricted:
print("Your app is not authorized to access the photo library, and the user cannot grant such permission.")
default: break
}
}
// opens the image picker for photo library
@objc func openPicker(_ gesture: UITapGestureRecognizer) {
galleryPicker.sourceType = .photoLibrary
galleryPicker.delegate = self
present(galleryPicker, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.imageView.contentMode = .scaleAspectFit
// check if there is an url saved in the user defaults
// and fetch its first object (PHAsset)
if let assetURL = UserDefaults.standard.url(forKey: "assetURL") {
if let asset = PHAsset.fetchAssets(withALAssetURLs: [assetURL], options: nil).firstObject {
asset.asyncImageData { data, _, _, _ in
print("fetched")
guard let data = data else { return }
self.imageView.image = UIImage(data: data)
}
} else {
print("assetURL:", assetURL)
self.imageView.image = UIImage(contentsOfFile: assetURL.path)
}
} else {
print("no assetURL found")
}

}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true)
print("canceled")
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

self.imageView.image = info[.originalImage] as? UIImage
if let phAsset = info[.phAsset] as? PHAsset {
phAsset.asyncURL { url in
guard let url = url else { return }
UserDefaults.standard.set(url, forKey: "assetURL")
print("assetURL saved")
}
}
dismiss(animated: true)
}
}

extension PHAsset {
func asyncURL(_ completion: @escaping ((URL?) -> Void)) {
switch mediaType {
case .image:
let options: PHContentEditingInputRequestOptions = .init()
options.canHandleAdjustmentData = { _ in true }
requestContentEditingInput(with: options) { editingInput, _ in
completion(editingInput?.fullSizeImageURL)
}
case .video:
let options: PHVideoRequestOptions = .init()
options.version = .original
PHImageManager.default()
.requestAVAsset(forVideo: self, options: options) { asset, _, _ in
completion((asset as? AVURLAsset)?.url)
}
default:
completion(nil)
}
}
func asyncImageData(version: PHImageRequestOptionsVersion = .original, completion: @escaping (Data?, String?, UIImage.Orientation, [AnyHashable : Any]?) -> ()) {
let options = PHImageRequestOptions()
options.version = version
PHImageManager.default()
.requestImageData(for: self, options: options, resultHandler: completion)
}
}
extension URL {
var phAsset: PHAsset? {
PHAsset.fetchAssets(withALAssetURLs: [self], options: nil).firstObject
}
}

Note: Don't forget to edit your info plist and add "Privacy - Photo Library Usage Description"

Sample

No permission to pick a photo from the photo library

The issue is that my users are able to access the photo library without getting a request alert to access their photo library

That is not an "issue". That is correct behavior.

The UIImagePickerController (or, in iOS 14, the PHPickerViewController) does not require user authorization for the photo library. That's because your app is not accessing the photo library! The runtime is accessing it, and the user is willingly handing you a photo. You receive the photo, not as a full-fledged photo in the library — that would be a PHAsset — but as a mere UIImage. So all you are getting is disembodied images.

If you wanted to turn around and fetch the PHAsset and look into the library, you would need user authorization. But you are just asking for the .editedImage, so you don't need user authorization.

If the .editedImage is nil, that's because it's the wrong key; if the user didn't edit the image, what you want is the .originalImage. And you still won't need authorization.

If you want to ask the system to present the alert that requests authorization, go ahead and ask it to do that. But the user won't get the alert by magic merely because you use the picker.



Related Topics



Leave a reply



Submit