haplo1384 haplo1384 - 1 day ago 4
iOS Question

Get PHAsset from iOS Share Extension

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?

Answer

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
                }
            }
    }
Comments