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

如何获取Files.app复制到UIPasteboard的文件夹实际数据并下载?

解决从Files.app复制文件夹后获取实际内容的问题

嘿,这个问题我之前也折腾过好一阵!从Files.app复制文件夹后拿到<NSFileProviderItem>的私有FPItem确实有点棘手——它只是一个指向云端/外部存储的「占位符」,不是本地可直接访问的文件。下面是我亲测有效的解决方案,一步步来:


1. 从FPItem中提取关键标识

虽然FPItem是私有类,但它遵循公开的NSFileProviderItem协议,我们可以通过KVC安全提取协议要求的核心属性(只要苹果不修改协议键名,这个方法就比较稳定):

// 假设你已经解归档得到了FPItem实例
guard let fpItem = unarchivedObject as? NSObject,
      let itemIdentifier = fpItem.value(forKey: "itemIdentifier") as? NSFileProviderItemIdentifier,
      let providerIdentifier = fpItem.value(forKey: "providerIdentifier") as? String else {
    print("无法提取FPItem的关键信息")
    return
}

2. 获取对应的File Provider管理器

每个文件服务(比如Dropbox、iCloud)都有专属的NSFileProviderManager实例,用刚才拿到的providerIdentifier就能获取到它:

guard let fileProviderManager = NSFileProviderManager(for: providerIdentifier) else {
    print("无法获取对应文件服务的管理器")
    return
}

3. 提交文件夹下载请求

向管理器提交下载请求,这个操作会触发系统把云端/外部存储的文件夹同步到本地设备:

fileProviderManager.requestDownload(for: [itemIdentifier]) { error in
    if let error = error {
        print("下载请求失败:\(error.localizedDescription)")
        return
    }
    // 下载请求已提交,接下来需要等待文件同步完成
    self.waitForFileToBeAvailable(itemID: itemIdentifier, manager: fileProviderManager)
}

4. 监听文件可用状态

下载是异步操作,我们需要轮询检查文件夹是否已经同步到本地(也可以结合NSFileProvider相关通知,但轮询实现更简单直接):

private func waitForFileToBeAvailable(itemID: NSFileProviderItemIdentifier, manager: NSFileProviderManager) {
    manager.fetchItem(withIdentifier: itemID) { [weak self] item, error in
        guard let self = self else { return }
        if let error = error {
            print("获取文件状态失败:\(error.localizedDescription)")
            return
        }
        guard let fileItem = item else {
            print("目标文件夹不存在")
            return
        }
        
        // 检查文件是否已完成下载并本地可用
        if fileItem.isDownloaded, let folderURL = fileItem.url {
            // 文件夹已经准备好,可以处理内容了
            self.processLocalFolder(at: folderURL)
        } else {
            // 还在下载中,0.5秒后再次检查
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.waitForFileToBeAvailable(itemID: itemID, manager: manager)
            }
        }
    }
}

5. 处理本地文件夹内容

拿到本地可用的文件夹URL后,就可以用常规的FileManager API读取内容了:

private func processLocalFolder(at folderURL: URL) {
    do {
        let contents = try FileManager.default.contentsOfDirectory(
            at: folderURL,
            includingPropertiesForKeys: [.isDirectoryKey],
            options: .skipsHiddenFiles
        )
        
        for itemURL in contents {
            let isDirectory = try itemURL.resourceValues(forKeys: [.isDirectoryKey]).isDirectory ?? false
            if isDirectory {
                print("找到子文件夹:\(itemURL.lastPathComponent)")
                // 递归处理子文件夹(如果需要)
                self.processLocalFolder(at: itemURL)
            } else {
                print("找到文件:\(itemURL.lastPathComponent)")
                // 处理单个文件逻辑
            }
        }
    } catch {
        print("读取文件夹内容失败:\(error.localizedDescription)")
    }
}

注意事项

  • 私有API风险:虽然用KVC提取属性是基于公开协议的,但FPItem毕竟是私有类,未来iOS版本可能有变化,建议添加容错处理(比如用responds(to:)检查属性是否存在)。
  • 权限配置:确保你的应用在Info.plist中添加了NSFileProviderDomainUsageDescription权限描述,避免被系统拒绝访问。
  • 批量下载:requestDownload方法默认会下载文件夹的所有子内容,不需要单独处理子文件/文件夹。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:00:13