Search code examples
iosswiftuiimagepickercontrollerphasset

How to get an authorized PHAsset from UIImagePickerController?


I have this code:

@IBAction func importButtonPressed(_ sender: Any) {
        self.imagePicker.sourceType = .photoLibrary
        self.imagePicker.allowsEditing = true
        self.imagePicker.mediaTypes = [kUTTypeMovie as String, kUTTypeImage as String]

        self.present(self.imagePicker,animated: true, completion: nil)
}

This presents the UIImagePicker perfectly. Then when I want to use the picked item to get say the date of the PHAsset:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        guard info[UIImagePickerControllerMediaType] != nil else { return }
        let mediaType = info[UIImagePickerControllerMediaType] as! CFString
        switch mediaType {
        case kUTTypeImage:
            if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
                ...
            }
            break
        case kUTTypeMovie:
            if let videoURL = info[UIImagePickerControllerMediaURL] as? URL, let pickedAsset = info[UIImagePickerControllerPHAsset] as? PHAsset {
                print("kUTTypeMovie")
                MyVariables.isScreenshot = false
                let creationDate = pickedAsset.creationDate
                print(creationDate,"creationDate")
            }
            break
        case kUTTypeLivePhoto:
            print("livePhoto")
            dismiss(animated: true, completion: nil)

            break
        default:
            dismiss(animated: true, completion: nil)

            print("something else")
            break
        }
    }

Now, when I pick a video for instance,print("kUTTypeMovie") fails I think because let pickedAsset = info[UIImagePickerControllerPHAsset] as? PHAsset fails

Elsewhere (UIImagePickerControllerDelegate get date from picked image in iOS 11) I have seen that perhaps this is because I need authorization to pick PHAssets.

So I change my first block of code to:

@IBAction func importButtonPressed(_ sender: Any) {

        let status = PHPhotoLibrary.authorizationStatus()

        switch status {
        case .authorized:
            PHPhotoLibrary.requestAuthorization({status in
                if status == .authorized {
                    self.imagePicker.sourceType = .photoLibrary
                    self.imagePicker.allowsEditing = true
                    self.imagePicker.mediaTypes = [kUTTypeMovie as String, kUTTypeImage as String]

                    self.present(self.imagePicker,animated: true, completion: nil)
                }
            })
        case .denied:
            print("denied")
        // probably alert the user that they need to grant photo access
        case .notDetermined:
            print("not determined")
        case .restricted:
            print("restricted")
            // probably alert the user that photo access is restricted
        }

    }

However now when I press the import button it crashes with an lldb error:

libsystem_kernel.dylib`__abort_with_payload:
    0x1854f7040 <+0>:  mov    x16, #0x209
    0x1854f7044 <+4>:  svc    #0x80
->  0x1854f7048 <+8>:  b.lo   0x1854f7060               ; <+32>
    0x1854f704c <+12>: stp    x29, x30, [sp, #-0x10]!
    0x1854f7050 <+16>: mov    x29, sp
    0x1854f7054 <+20>: bl     0x1854d8bdc               ; cerror_nocancel
    0x1854f7058 <+24>: mov    sp, x29
    0x1854f705c <+28>: ldp    x29, x30, [sp], #0x10
    0x1854f7060 <+32>: ret    

So clearly I am not doing that correctly. How am I supposed to do this?


Solution

  • The crash is because of the below missing permission to access the photo library,

    This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.

    In your Info.plist, add NSPhotoLibraryUsageDescription key with some description as below and it will work fine

    enter image description here

    Edit You should also use the PhotoLibrary authorization in proper way as below.

    @IBAction func importButtonPressed(_ sender: Any) {
    
        PHPhotoLibrary.requestAuthorization({status in
            switch status {
            case .authorized:
                self.imagePicker.sourceType = .photoLibrary
                self.imagePicker.allowsEditing = true
                self.imagePicker.mediaTypes = [kUTTypeMovie as String, kUTTypeImage as String]
    
                self.present(self.imagePicker,animated: true, completion: nil)
            case .denied:
                print("denied")
            // probably alert the user that they need to grant photo access
            case .notDetermined:
                print("not determined")
            case .restricted:
                print("restricted")
                // probably alert the user that photo access is restricted
            }
        })
    }