下面给你一个 全面、可直接落地的「沙盒文件 → iCloud Document」移动/迁移操作清单,包括需要的 API、注意事项、元数据同步、进度处理等。确保你能在自己的文件管理 App 中正确实现。
✅ 一、涉及的目录
1. 沙盒目录(App 内部)
例如:
Documents/Library/tmp/
这些都只能本地访问。
2. iCloud Document(基于 UIDocument / NSFileManager)
通常是:
let ubiquityURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent("Documents")
用户的 iCloud 会自动同步该目录。
✅ 二、移动文件的本质步骤
沙盒 → iCloud 本质是两个操作:
- 拷贝/移动本地文件到 Ubiquity Container
- 让 iCloud 接管该文件并同步
⚙️ 步骤 1:获取 iCloud Document 目录 URL
guard let containerURL = FileManager.default.url(
forUbiquityContainerIdentifier: nil
)?.appendingPathComponent("Documents") else {
print("iCloud 未启用")
return
}
try FileManager.default.createDirectory(
at: containerURL,
withIntermediateDirectories: true,
attributes: nil
)
⚙️ 步骤 2:执行文件移动/复制
🔹 推荐:copy → remove(比 move 更稳定)
Apple 官方不建议直接 move,因为 iCloud 目录是特殊文件系统。
let source = localURL // 沙盒文件
let destination = containerURL.appendingPathComponent(source.lastPathComponent)
do {
try FileManager.default.copyItem(at: source, to: destination)
// 拷贝成功后删除本地
try FileManager.default.removeItem(at: source)
} catch {
print("移动失败:\(error)")
}
⚙️ 步骤 3:启动 iCloud 对文件的管理
对于 Ubiquity 文件,iCloud 会自动同步,但你可以手动触发:
var values = URLResourceValues()
values.isExcludedFromBackup = false
try? destination.setResourceValues(values)
⚙️ 步骤 4:监听 iCloud 同步状态(可选)
监听 NSMetadataQueryDidUpdate 或 NSMetadataQueryDidFinishGathering:
query = NSMetadataQuery()
query.predicate = NSPredicate(format: "%K like '*'", NSMetadataItemFSNameKey)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
在回调里获取文件状态:
let status = item.value(forAttribute: NSMetadataUbiquitousItemDownloadingStatusKey) as? String
可返回:
currentdownloadednotDownloaded
⚙️ 步骤 5:上传进度(iCloud 上传)
iCloud 对上传没有 progress API,但你可以:
✔ 监听 NSMetadataItemPercentUploadedKey
if let percent = item.value(forAttribute: NSMetadataUbiquitousItemPercentUploadedKey) as? Double {
print("上传进度:\(percent)")
}
⚙️ 步骤 6:冲突处理
当用户另一台设备编辑了同一文件,你会收到:
NSFileVersion冲突
let unresolved = NSFileVersion.unresolvedConflictVersionsOfItem(at: url) ?? []
for version in unresolved {
version.isResolved = true
}
也可以让 UIDocument 自动合并。
👉 关键提醒(非常重要)
1. 不要使用 FileManager.moveItem 直接移动
因为沙盒 → iCloud 是不同文件系统,有时会失败或导致文件丢失。
正确策略:
✔ 复制
✔ 校验
✔ 删除原文件
2. 在 iCloud 目录中的文件自动同步,不需要你上传
唯一要做的事就是把文件放到 iCloud Document 文件夹里。
3. 大文件复制要用后台队列
避免阻塞主线程:
DispatchQueue.global().async {
try? FileManager.default.copyItem(...)
}
4. 不要把整个目录移动到 iCloud
建议文件级迁移,不建议目录级 move。
📌 最佳实践的完整方法(可直接用)
func moveToICloud(from localURL: URL) throws -> URL? {
guard let container = FileManager.default.url(
forUbiquityContainerIdentifier: nil
)?.appendingPathComponent("Documents") else {
return nil
}
try FileManager.default.createDirectory(at: container, withIntermediateDirectories: true)
let dest = container.appendingPathComponent(localURL.lastPathComponent)
// copy
try FileManager.default.copyItem(at: localURL, to: dest)
// delete local
try FileManager.default.removeItem(at: localURL)
return dest
}
如果你愿意,我可以帮你:
✔ 设计你文件管理 App 的 iCloud 文件操作架构
✔ 提供下载、上传、同步、冲突、进度的完整代码
✔ 优化你的 NSMetadataQuery
✔ 做成可复用模块(Protocol + Manager)
你现在想了解哪个部分?