System & Services 进阶 20m
CloudKit 新变化
What's new in CloudKit
2021年6月10日
一句话判断
CloudKit 这次的更新主要是”运维友好”方向:共享记录的权限细化、CloudKit Console 的 Web 版、以及 Schema 变更的声明式管理 —— 但如果你没用过 CloudKit,这些改进无法吸引你从 Firebase 迁移过来。
这场 Session 讲了什么
Session 介绍了 CloudKit 在 iOS 15 / macOS 12 中的多项改进。重点包括:
- 共享记录(Shared Records)的权限增强。开发者可以更细粒度地控制共享行为:只读/读写权限、自定义共享 UI、以及通过
CKShare的权限层级(owner/participant)管理。 - CloudKit Console(Web 控制台)。全新的 Web 版管理工具,可以直接在浏览器中查看和操作 CloudKit 数据库,包括查询记录、修改 Schema、查看日志。不再依赖 CloudKit Dashboard 的旧版界面。
- 声明式 Schema 管理。通过 JSON 配置文件定义 Schema 变更,结合新的
cktool命令行工具实现 Schema 的自动化部署,适合 CI/CD 流水线。 - 性能监控。CloudKit Console 中新增了 API 请求延迟和错误率的监控面板。
值得深挖的点
声明式 Schema 和 cktool 命令行工具。以前 CloudKit 的 Schema 管理只能通过 CloudKit Dashboard 的 Web UI 手动操作,或者通过代码隐式创建(在 Development 环境中写入一条新类型记录)。现在可以用 JSON 文件声明式定义 Record Type、Field、Index,然后通过 cktool 一键部署。这对团队协作和多环境管理意义重大 —— Schema 变更可以 code review、版本控制、自动部署。
CKShare 的自定义权限 UI。新的 UICloudSharingController 允许开发者自定义共享界面的选项,比如限制参与者只能查看不能编辑、设置共享链接的过期时间。在多人协作类 app(如文档编辑、项目管理)中,这比以前灵活得多。
代码片段
创建带权限控制的共享记录:
import CloudKit
func shareRecord(_ record: CKRecord) {
// 创建共享对象
let share = CKShare(rootRecord: record)
share[CKShare.SystemFieldKey.title] = "协作文档"
// 设置权限:参与者可编辑
share.allowAnyoneToModify = true // 允许任何人通过链接编辑
// 保存记录和共享
let container = CKContainer.default()
let database = container.privateCloudDatabase
let operation = CKModifyRecordsOperation(
recordsToSave: [record, share],
recordIDsToDelete: nil
)
operation.modifyRecordsResultBlock = { result in
switch result {
case .success:
print("共享创建成功")
case .failure(let error):
print("共享失败: \(error)")
}
}
database.add(operation)
}
使用 cktool 管理 Schema:
# 导出当前 Schema 到 JSON 文件
cktool schema export --container MyContainer --environment development > schema.json
# 编辑 schema.json 后,应用到开发环境
cktool schema apply --container MyContainer --environment development --input schema.json
# 将 Schema 从开发环境推送到生产环境
cktool schema promote --container MyContainer
查询 CloudKit 数据(带分页):
import CloudKit
func queryRecordsWithPagination() {
let query = CKQuery(recordType: "Task", predicate: NSPredicate(value: true))
query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let operation = CKQueryOperation(query: query)
operation.resultsLimit = 50 // 每页 50 条
operation.recordFetchedBlock = { record in
print("获取到记录: \(record.recordID)")
}
operation.queryResultBlock = { result in
switch result {
case .success(let cursor):
// 还有更多数据,使用 cursor 继续查询
if let cursor = cursor {
self.fetchNextPage(cursor: cursor)
}
case .failure(let error):
print("查询失败: \(error)")
}
}
CKContainer.default().publicCloudDatabase.add(operation)
}
最佳实践
- 把 Schema JSON 文件纳入版本控制。声明式 Schema 的最大价值是可追溯,每次变更都有 commit 记录。如果 Schema 改坏了,可以精确回滚。
- 共享记录的 UI 要处理好权限冲突。当两个参与者同时编辑同一字段时,CloudKit 采用 last-write-wins 策略。对于关键数据,在 app 层实现乐观锁(Optimistic Locking)。
- 用 CloudKit Console 的监控面板定期检查 API 延迟。如果请求延迟超过 500ms,大概率是查询没有命中索引。去 Schema 配置中给常用查询字段添加索引。
还有什么值得关注
- CloudKit Console 支持直接在浏览器中执行 CKQuery,方便调试数据问题。
CKDatabase的 batch 操作现在支持原子提交(Atomic Zone),要么全部成功要么全部回滚。- CloudKit 的免费额度保持不变:每天 40 次请求/秒、每天 250MB 存储、每天 2GB 传输。
WWDC 2021