0

I'm building a swift iMessage extension where a user picks images from their camera roll. I'd like to show their camera roll in the collapsed message view so that users can select their photos without needing to expand the iMessage Extension to fullscreen.

Normally I'd use the PhotosPicker or PhotosUI, but that opens a bottomsheet modal and looks pretty bad in the small space.

embedded modal photo picker

How can I embed the camera roll directly without the modal presentation? Is there a 3rd party library that has a photo picker in a swiftUI view?

  • Welcome to Stack Overflow! Please take the [tour](https://stackoverflow.com/tour) and see: [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Reproducible Example (MRE)](https://stackoverflow.com/help/minimal-reproducible-example). – Yrb Aug 01 '23 at 16:03

1 Answers1

0

According to the latest WWDC for the PhotoPicker, and you can read the transcript here, iOS 17 is coming out with the ability to customize and embed the inline photo picker. Unfortunately for me and my problem, that's not publicly available until September 2023. So for now, you can do something like this to embed the picker directly into a view controller:

// Create a PHPickerConfiguration
    var configuration = PHPickerConfiguration(photoLibrary: .shared())
    configuration.selectionLimit = 4 // Set the selection limit to 4 images
    configuration.filter = .images // Set the filter to images only
    
    // Create a PHPickerViewController with the configuration
    let picker = PHPickerViewController(configuration: configuration)
    picker.delegate = self // Set the delegate to self
    
    // Add the picker as a child view controller
    addChild(picker)
    
    // Set the frame of the picker, or use Auto Layout constraints
    picker.view.frame = view.bounds
    
    // Add the picker’s view as a subview
    view.addSubview(picker.view)
    
    // Notify the picker that it has been added
    picker.didMove(toParent: self)

However, this still looks pretty bad in the iMessage extension because you can't turn off the extra UI so it's very cramped in the half sheet.

The other option is asking for camera roll permissions and making your own picker. The downside here is that if the user doesn't allow permissions, or selects certain photos, you're out of luck and it's really hard to get them to find where to turn the permissions back on again. Additionally, you're now on the hook for all the image management. Here's a snippet I wrote to fetch the first 20 images from the camera roll:

func loadImages() {
    PHPhotoLibrary.requestAuthorization({ (status) -> Void in
      switch status {
      case .authorized:
        break
      default:
        // We didn't get access
        return
      }
    })
    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    fetchOptions.fetchLimit = 20
    
    let result = PHAsset.fetchAssets(with: .image, options: fetchOptions)
    result.enumerateObjects { (asset, _, _) in
      let manager = PHImageManager.default()
      let option = PHImageRequestOptions()
      option.isSynchronous = true
      manager.requestImage(for: asset,
                           targetSize: CGSize(width: 300, height: 300),
                           contentMode: .aspectFit,
                           options: option,
                           resultHandler: { (image, _) in
        if let image = image {
          self.images.append(image)
        }
      })
    }
  }

Finally, the solution I came to was to cut scope and just have a button to expand the iMessage extension to the full sheet, and then the users can select images using the system picker fullscreen. It's a bummer, but I can revisit this answer once iOS 17 drops.