You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 15.5下Share Extension无法获取截图数据的技术求助

iOS 15.5 Share Extension 无法获取截图数据问题

环境

  • iOS 15.5

现有代码

override func didSelectPost() {
   if let extensionItems = self.extensionContext?.inputItems as? [NSExtensionItem]  {
      let attachments     = extensionItems.first?.attachments ?? []
      let imageType       = UTType.image.identifier
      
      for provider in attachments {
         if provider.hasItemConformingToTypeIdentifier(imageType) {
            print("It is an image")

            // this seems only to handle media from photos
            provider.loadFileRepresentation(forTypeIdentifier: imageType) { (unsafeFileUrl, error) in
               print("We have the image")
            }
         }
      }
   }
}

实际表现

  • 从照片应用分享图片时,didSelectPost()运行正常,能获取到图片数据
  • 从系统截图分享按钮分享时,能打印"It is an image",但loadFileRepresentation的闭包从未触发,无法获取图片数据

已尝试方案

  • 改用loadItem、loadDataRepresentation方法获取数据,同样无法触发闭包内的打印语句
  • 参考相关问题但未解决

预期效果

成功获取截图的图片数据并保存到本地磁盘

疑问

  1. 为什么截图的图片数据无法被访问?
  2. 正确的访问方式是什么?

解决方案

问题核心是Share Extension的生命周期问题:默认情况下,didSelectPost执行完毕后系统会立即关闭扩展,而loadFileRepresentation等方法是异步执行的,闭包还没来得及运行就被终止了。

修改代码如下:

import UniformTypeIdentifiers

override func didSelectPost() {
    // 禁止系统自动关闭扩展,手动控制结束时机
    guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem],
          let attachments = extensionItems.first?.attachments,
          !attachments.isEmpty else {
        extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
        return
    }
    
    let imageType = UTType.image.identifier
    
    for provider in attachments {
        guard provider.hasItemConformingToTypeIdentifier(imageType) else { continue }
        
        print("It is an image")
        
        provider.loadFileRepresentation(forTypeIdentifier: imageType) { [weak self] fileUrl, error in
            guard let self = self else { return }
            
            if let error = error {
                print("加载图片失败: \(error.localizedDescription)")
                self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
                return
            }
            
            guard let fileUrl = fileUrl else {
                print("图片URL为空")
                self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
                return
            }
            
            print("We have the image: \(fileUrl.path)")
            
            // 执行保存图片到磁盘的逻辑
            self.saveImageToDisk(from: fileUrl)
            
            // 操作完成后手动关闭扩展
            self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
        }
        // 找到第一个符合条件的资源后停止遍历(可根据需求调整)
        break
    }
}

private func saveImageToDisk(from fileUrl: URL) {
    // 示例:保存到App Group共享目录(需提前配置App Group)
    let appGroupIdentifier = "你的App Group ID"
    guard let sharedContainerUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) else {
        print("无法获取共享容器")
        return
    }
    
    let destinationUrl = sharedContainerUrl.appendingPathComponent("screenshot_\(Date().timeIntervalSince1970).png")
    
    do {
        try FileManager.default.copyItem(at: fileUrl, to: destinationUrl)
        print("图片保存成功: \(destinationUrl.path)")
    } catch {
        print("保存图片失败: \(error.localizedDescription)")
    }
}

关键修改点

  1. 手动控制生命周期:移除系统默认的自动关闭逻辑,在异步操作完成(成功/失败)后调用extensionContext?.completeRequest手动结束扩展
  2. 弱引用避免内存泄漏:闭包中使用[weak self]防止循环引用
  3. 健壮性处理:添加错误、空值判断,确保流程不会异常中断
  4. 共享容器配置(可选):如果需要将截图同步给主App,需在Xcode中配置App Group,使用共享目录存储文件

内容的提问来源于stack exchange,提问作者airs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:36:18