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

iOS Share Extension加载WhatsApp Zip附件无法正常工作

问题描述

读取WhatsApp导出的聊天记录Zip文件时,Share Extension无法正常加载WhatsApp Zip附件。
当前实现代码如下:

override func viewDidLoad() {
    super.viewDidLoad()
    getURL()
}

private func getURL() {
    let extensionItem = extensionContext?.inputItems.first as! NSExtensionItem
    let itemProvider = extensionItem.attachments?.first
    let zip_type = String(UTType.zip.identifier)
    if itemProvider!.hasItemConformingToTypeIdentifier(zip_type) {
        itemProvider!.loadItem(forTypeIdentifier: zip_type, options: nil, completionHandler: { (item, error) -> Void in
            guard let url = item as? NSURL else { return }
            OperationQueue.main.addOperation {
                print("url\(url)")
                self.path = url as URL

                do {
                    let unzipDirectory = try Zip.quickUnzipFile(self.path)
                    print("unzipDirectory\(unzipDirectory)")
                   
                    if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
                        let fileURL = dir.appendingPathComponent(unzipDirectory.lastPathComponent)
                        print("fileURL\(fileURL)")
                        do {
                               let text2 = try String(contentsOf: fileURL, encoding: .utf8)
                            print(text2)
                           }
                           catch {/* error handling here */}
                }
            }
                catch {
                    print("Something went wrong")
                }

            }
        })
    } else {
        print("error")
    }
}
override func isContentValid() -> Bool {
    print("Hiii")
    // Do validation of contentText and/or NSExtensionContext attachments here
    return true
}

override func didSelectPost() {
    print("hello")
    self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
    
}

override func configurationItems() -> [Any]! {
    // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
    return []
}

运行控制台输出错误:

[core] SLComposeServiceViewController got attachment coarseType 0
[core] SLComposeServiceViewController made no attachment for itemProvider conforming to public.file-url

问题原因

控制台输出的两条日志,由三个核心问题导致:

  1. WhatsApp分享zip附件时,不会直接暴露UTType.zip类型给Share Extension,而是先暴露public.file-url类型,当前代码只判断zip类型,根本匹配不到传入的附件,系统默认的SLComposeServiceViewController识别不到符合规则的附件就会打印这两条log。
  2. 从Extension拿到的外部文件URL属于安全域资源,直接访问/解压会因为权限不足失败,必须先调用安全访问方法拿到操作权限。
  3. 原代码逻辑存在两处硬伤:一是强制解包输入项、附件对象,遇到多附件场景会直接崩溃;二是解压后把返回的目录路径直接当文件路径读取,根本拿不到聊天内容。
修复步骤
  • 第一步:修改Info.plist里的Extension激活规则,在NSExtensionActivationRule下新增支持public.file-url和public.zip-archive两种类型,确保系统能把WhatsApp的分享请求传给你的Extension。
  • 第二步:替换原有getURL()方法逻辑,先匹配文件URL类型,拿到URL后校验文件后缀是否为zip,过滤无关文件。
  • 第三步:拿到URL后先调用startAccessingSecurityScopedResource()获取访问权限,操作结束后调用stopAccessingSecurityScopedResource()释放权限,把zip文件拷贝到自身Extension的沙盒临时目录后再做解压操作,禁止直接操作原路径。
  • 第四步:解压完成后遍历解压目录,找到后缀为txt的聊天记录文件再读取内容,不要直接把解压目录当文件读取。

修复后的核心代码:

private func getURL() {
    guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else { return }
    let fileUrlType = UTType.fileURL.identifier
    
    for extensionItem in extensionItems {
        guard let attachments = extensionItem.attachments else { continue }
        for itemProvider in attachments {
            if itemProvider.hasItemConformingToTypeIdentifier(fileUrlType) {
                itemProvider.loadItem(forTypeIdentifier: fileUrlType, options: nil) { [weak self] item, error in
                    guard let self = self, error == nil, let url = item as? URL else { return }
                    // 获取安全域访问权限
                    guard url.startAccessingSecurityScopedResource() else { return }
                    defer { url.stopAccessingSecurityScopedResource() }
                    // 校验文件是否为zip格式
                    guard url.pathExtension.lowercased() == "zip" else { return }
                    
                    OperationQueue.main.addOperation {
                        do {
                            // 拷贝文件到自身沙盒临时目录
                            let tempZipPath = FileManager.default.temporaryDirectory.appendingPathComponent(url.lastPathComponent)
                            if FileManager.default.fileExists(atPath: tempZipPath.path) {
                                try FileManager.default.removeItem(at: tempZipPath)
                            }
                            try FileManager.default.copyItem(at: url, to: tempZipPath)
                            
                            // 执行解压
                            let unzipFolder = try Zip.quickUnzipFile(tempZipPath)
                            // 遍历解压目录查找txt聊天文件
                            if let allFiles = try? FileManager.default.contentsOfDirectory(at: unzipFolder, includingPropertiesForKeys: nil) {
                                for file in allFiles where file.pathExtension.lowercased() == "txt" {
                                    if let chatContent = try? String(contentsOf: file, encoding: .utf8) {
                                        print("读取到聊天内容:\(chatContent)")
                                        // 后续业务逻辑在此处处理
                                    }
                                }
                            }
                        } catch {
                            print("文件处理失败:\(error.localizedDescription)")
                        }
                    }
                }
                return
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:51:17