8

I am developing a share extension for photos for my iOS app. Inside the extension, I am able to successfully retrieve the UIImage object from the NSItemProvider.

However, I would like to be able to share the image with my container app, without having to store the entire image data inside my shared user defaults. Is there a way to get the PHAsset of the image that the user has chosen in the share extension (if they have picked from their device)?

The documentation on the photos framework (https://developer.apple.com/library/ios/documentation/Photos/Reference/Photos_Framework/) has a line that says "This architecture makes it easy, safe, and efficient to work with the same assets from multiple threads or multiple apps and app extensions."

That line makes me think there is a way to share the same PHAsset between extension and container app, but I have yet to figure out any way to do that? Is there a way to do that?

haplo1384
  • 1,206
  • 1
  • 12
  • 29

2 Answers2

9

This only works if the NSItemProvider gives you a URL with the format:

file:///var/mobile/Media/DCIM/100APPLE/IMG_0007.PNG

which is not always true for all your assets, but if it returns a URL as:

file:///var/mobile/Media/PhotoData/OutgoingTemp/2AB79E02-C977-4B4A-AFEE-60BC1641A67F.JPG

then PHAsset will never find your asset. Further more, the latter is a copy of your file, so if you happen to have a very large image/video, iOS will duplicate it in that OutgoingTemp directory. Nowhere in the documentation says when it's going to be deleted, hopefully soon enough.

I think this is a big gap Apple has left between Sharing Extensions and PHPhotoLibrary framework. Apple should've be creating an API to close it, and soon.

carlos_ms
  • 838
  • 9
  • 15
  • I see apps working with the OutgoingTemp as well, but have not determined how yet. – Danny Jan 23 '17 at 18:08
  • @a-r-studios maybe we can examine image's creation date from the file's metadata (EXIF), then match with PHAsset.creationDate? – Jonny Feb 06 '17 at 06:45
  • 1
    any update on this ? I mean, we have 2021 now - and Apple should hopefully have addressed this issue by now, shouldn't they ? – iKK Jan 16 '21 at 13:57
6

You can get PHAsset if image is shared from Photos app. The item provider will give you a URL that contains the image's filename, you use this to match PHAsset.

/// Assets that handle through handleImageItem:completionHandler:
private var handledAssets = [PHAsset]()

/// Key is the matched asset's original file name without suffix. E.g. IMG_193
private lazy var imageAssetDictionary: [String : PHAsset] = {

    let options = PHFetchOptions()
    options.includeHiddenAssets = true

    let fetchResult = PHAsset.fetchAssetsWithOptions(options)

    var assetDictionary = [String : PHAsset]()

    for i in 0 ..< fetchResult.count {
        let asset = fetchResult[i] as! PHAsset
        let fileName = asset.valueForKey("filename") as! String
        let fileNameWithoutSuffix = fileName.componentsSeparatedByString(".").first!
        assetDictionary[fileNameWithoutSuffix] = asset
    }

    return assetDictionary
}()

...

provider.loadItemForTypeIdentifier(imageIdentifier, options: nil) { imageItem, _ in
    if let image = imageItem as? UIImage {
      // handle UIImage
    } else if let data = imageItem as? NSData {
      // handle NSData 
    } else if let url = imageItem as? NSURL {
         // Prefix check: image is shared from Photos app
         if let imageFilePath = imageURL.path where imageFilePath.hasPrefix("/var/mobile/Media/") {
             for component in imageFilePath.componentsSeparatedByString("/") where component.containsString("IMG_") {

        // photo: /var/mobile/Media/DCIM/101APPLE/IMG_1320.PNG
        // edited photo: /var/mobile/Media/PhotoData/Mutations/DCIM/101APPLE/IMG_1309/Adjustments/FullSizeRender.jpg

                // cut file's suffix if have, get file name like IMG_1309.
                let fileName = component.componentsSeparatedByString(".").first!
                if let asset = imageAssetDictionary[fileName] {
                    handledAssets.append(asset)
                    imageCreationDate = asset.creationDate
                }
                    break
                }
            }
    }
Jonny
  • 1,969
  • 18
  • 25
  • This will probably work, but until apple changes something in the image file path, which may not be likely. I am thinking after all it may be better to store the data in user defaults, retrieve it in the main app and then clean it up again. Advantage of user default is that you are not dependant that the user may delete the PHAsset. – Samuël Sep 09 '22 at 15:34
  • 1
    @Samuël you can always save media data with varies ways. The problem here is that if you need to link the media data with an asset in user's Photo Library you have to get a `PHAsset` in some way. Why would someone need that? For example, an image editor app may want to apply user editing info directly on the original `PHAsset` instead of creating a new, duplicated `PHAsset`. – Jonny Sep 19 '22 at 01:55