从iOS分享扩展获取PHAsset

8

我正在为我的iOS应用程序开发照片共享扩展。在扩展中,我能够成功地从NSItemProvider中检索到UIImage对象。

然而,我希望能够与我的容器应用程序共享图像,而不必将整个图像数据存储在我的共享用户默认值中。如果用户从他们的设备中选择了图像,是否有一种方法可以获取分享扩展中用户选择的图像的PHAsset呢?

照片框架的文档(https://developer.apple.com/library/ios/documentation/Photos/Reference/Photos_Framework/)上有一行话说:“这种架构使得从多个线程或多个应用程序和应用程序扩展中使用同一资源变得容易、安全、高效。”

这句话让我想到可能有一种方式可以在扩展和容器应用程序之间共享相同的PHAsset,但我还没有找到任何方法来实现它。是否有一种方法可以实现这一点呢?

2个回答

9
只有在NSItemProvider以以下格式提供URL时才有效:file:///var/mobile/Media/DCIM/100APPLE/IMG_0007.PNG。然而,并非所有资产都是如此,如果返回的URL是file:///var/mobile/Media/PhotoData/OutgoingTemp/2AB79E02-C977-4B4A-AFEE-60BC1641A67F.JPG,那么PHAsset将永远找不到您的资产。此外,后者是文件的副本,因此如果您恰好有一个非常大的图像/视频,则iOS会在该OutgoingTemp目录中复制它。文档中没有说明何时删除它,希望尽快解决。
我认为这是苹果在共享扩展和PHPhotoLibrary框架之间留下的巨大空白。苹果应该创建一个API来关闭它,而且应该尽快实现。

我看到应用程序也在使用OutgoingTemp,但还没有确定如何使用。 - Danny
@a-r-studios也许我们可以从文件的元数据(EXIF)中检查图像的创建日期,然后与PHAsset.creationDate进行匹配? - Jonny
1
这个问题有任何更新吗?我是说,现在已经是2021年了 - 苹果公司希望现在已经解决了这个问题,不是吗? - iKK

6

如果从照片应用程序共享图像,则可以获取PHAsset。项目提供程序将为您提供包含图像文件名的URL,您可以使用此URL来匹配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
                }
            }
    }

这可能有效,但在苹果更改图像文件路径之前,这可能不太可能发生。我想,毕竟,最好将数据存储在用户默认设置中,在主应用程序中检索它,然后再次清理它。用户默认设置的优点是您不依赖于用户可能删除PHAsset。 - Samuël
1
@Samuël,您可以通过多种方式保存媒体数据。问题在于,如果您需要将媒体数据与用户照片库中的资产链接起来,则必须以某种方式获取PHAsset。为什么有人需要这样做呢?例如,图像编辑应用程序可能希望直接在原始PHAsset上应用用户编辑信息,而不是创建新的、重复的PHAsset - Jonny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接