UIImagePickerController and PHPickerViewController image selection blank in iOS14

7.6k views Asked by At

Had this working on the last few versions of iOS but on 14 cannot get this to work, I have spent the past 5 days Googling.

Whenever I go to add an image from the gallery the popup to select an image is blank.

I have tried UIImagePickerController(which works fine iOS13 and below) and the new PHPickerViewController.

What has been working up until iOS14 is the user clicks a bar button to "add image" and the pop up asks to pick from the gallery and then presents the picker with images in your gallery.

I have set the Info.plist "Privacy - Photo Library Usage Description" for UIImagePickerController, I know the PHPickerViewController doesn't need perms as it handles getting the image for you.

I have also been seeing these purple warning now and again saying "xxxx must be used from main thread only", never seen that before until the new Xcode.

Any help would be much appreciated. Running Xcode 12.0.1 (12A7300), simulators running iOS14.

Adam

enter image description here

enter image description here

enter image description here

class AddCustomExerciseViewController: UIViewController, UITextViewDelegate, UINavigationControllerDelegate, GADBannerViewDelegate, UIImagePickerControllerDelegate, PHPickerViewControllerDelegate{

let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in self.openGallery() }))
        alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
        self.present(alert, animated: true, completion: nil)

func openGallery()
{
    let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
        switch photoAuthorizationStatus {
        case .authorized:
            self.showGallery()
            print("Access is granted by user")
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization({
                (newStatus) in
                print("status is \(newStatus)")
                if newStatus ==  PHAuthorizationStatus.authorized {
                    self.showGallery()
                    print("success")
                }
            })
            print("It is not determined until now")
        case .restricted:
            // same same
            print("User do not have access to photo album.")
        case .denied:
            // same same
            print("User has denied the permission.")
        case .limited:
            // same same
            print("User has denied the permission.")
        }
}

func showGallery()
{
    if #available(iOS 14, *)
    {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images
        configuration.selectionLimit = 0
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        self.present(picker, animated: true, completion: nil)
    }
    else
    {
                
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.allowsEditing = false
            imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
            self.present(imagePicker, animated: true, completion: nil)
        }
        else
        {
            let alert  = UIAlertController(title: "Warning", message: "You don't have permission to access gallery.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
        
        //get the file url
        if let fileUrl = info[UIImagePickerControllerImageURL] as? URL {
            print(fileUrl)
            print(fileUrl.lastPathComponent)
            let filePath = fileUrl.lastPathComponent
            
            if(filePath.hasSuffix("GIF")||filePath.hasSuffix("gif"))
            {
                //to change later to support gifs
                gifView.image = pickedImage
            }
            else
            {
                //to show the static image to users
                gifView.image = pickedImage
            }
            //for saving the file name to retrieve in local parse datastore
            imageNameToSave = fileUrl.lastPathComponent
        }
        //for saving the selected image
        imageToSave = pickedImage
    }
    picker.dismiss(animated: true, completion: nil)
}
@available(iOS 14, *)
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
{
   picker.dismiss(animated: true, completion: nil)
   for result in results
   {
      result.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { (object, error) in
         if let image = object as? UIImage {
            DispatchQueue.main.async {
               // Use UIImage
               print("Selected image: \(image)")
            }
         }
      })
   }
}  }
2

There are 2 answers

3
Mohit Padalia On

On iOS 14 the restricted image picker permission dialog opens in a separate thread, so when the authorization return you will need to perform UI tasks on main thread.

PHPhotoLibrary.requestAuthorization({
        (newStatus) in
    DispatchQueue.main.async {
        print("status is \(newStatus)")
        if newStatus ==  PHAuthorizationStatus.authorized {
            self.showGallery()
            print("success")
        }
    }
})
0
Azure On

If this is helpful for anyone else I discovered that editing the scrollview appearance proxy background caused a bug in both the UIImagePickerController and the PHPickerViewController preventing them from showing images in iOS 14 and above. I had edited the scrollview background proxy because it is black even in light mode. After hours of googling and testing I discovered that removing the appearance background modification on the scrollview proxy allowed the image pickers to function as expected. I filed a bug report with Apple. The line of code that caused the bug was:

UIScrollView.appearance().backgroundColor = .systemBackground