Importing an image using Action Extension - URL to a local Image works but not with actual image data

1.7k Views Asked by At

My iOS app (Swift 3) needs to important images from other apps using an Action Extension. I'm using the standard Action Extension template code which works just fine for apps like iOS Mail and Photos where the image shared is a URL to a local file. But for certain apps where the image being shared is the actual image data itself, my action extension code isn't getting the image.

  for item: Any in self.extensionContext!.inputItems {
        let inputItem = item as! NSExtensionItem
        for provider: Any in inputItem.attachments! {

            let itemProvider = provider as! NSItemProvider

            if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {  //we'll take any image type: gif, png, jpg, etc

        // This is an image. We'll load it, then place it in our image view.
        weak var weakImageView = self.imageView
        itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil, completionHandler: { (imageURL,

            error) in
            OperationQueue.main.addOperation {


                if let strongImageView = weakImageView {


                    if let imageURL = imageURL as? NSURL {

                        strongImageView.image = UIImage(data: NSData(contentsOf: imageURL as URL)! as Data)

                        let imageData = NSData(contentsOf: imageURL as URL)! as Data
                        self.gifImageView.image = UIImage.gif(data: imageData)

                        let width = strongImageView.image?.size.width
                        let height = strongImageView.image?.size.height
                        ....  my custom logic

                   }
              }  

For reference, I reached out to the developer for one of the apps where things aren't working and he shared this code on how he is sharing the image to the Action Extension.

//Here is the relevant code. At this point the scaledImage variable holds a UIImage. 

var activityItems = Array<Any?>()

if let pngData = UIImagePNGRepresentation(scaledImage) {

    activityItems.append(pngData)

} else {

    activityItems.append(scaledImage)
}

//Then a little later it presents the share sheet:

let activityVC = UIActivityViewController(activityItems: activityItems,applicationActivities: [])

self.present(activityVC, animated: true, completion: nil)              
1

There are 1 best solutions below

1
On

Figured it out thanks to this post which explains the challenge quite well https://pspdfkit.com/blog/2017/action-extension/ . In summary, we don't know if the sharing app is giving us a URL to an existing image or just raw image data so we need to modify the out of the box action extension template code to handle both cases.

for item: Any in self.extensionContext!.inputItems {
    let inputItem = item as! NSExtensionItem
    for provider: Any in inputItem.attachments! {

        let itemProvider = provider as! NSItemProvider

        if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {  //we'll take any image type: gif, png, jpg, etc

    // This is an image. We'll load it, then place it in our image view.
    weak var weakImageView = self.imageView
    itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil, completionHandler: { (imageURL,

        error) in
        OperationQueue.main.addOperation {


            if let strongImageView = weakImageView {


                if let imageURL = imageURL as? NSURL {

                    strongImageView.image = UIImage(data: NSData(contentsOf: imageURL as URL)! as Data)

                    let imageData = NSData(contentsOf: imageURL as URL)! as Data
                    self.gifImageView.image = UIImage.gif(data: imageData)

                    let width = strongImageView.image?.size.width
                    let height = strongImageView.image?.size.height
                    ....  my custom logic

               }

               else 

                    guard let imageData = imageURL as? Data else { return } //can we cast to image data?
                    strongImageView_.image = UIImage(data: imageData_)

                    //custom logic

          }