What's new in CloudKit
System & Services 进阶 20m

CloudKit 新变化

What's new in CloudKit

2021年6月10日

在 Apple 官方观看视频

一句话判断

CloudKit 这次的更新主要是”运维友好”方向:共享记录的权限细化、CloudKit Console 的 Web 版、以及 Schema 变更的声明式管理 —— 但如果你没用过 CloudKit,这些改进无法吸引你从 Firebase 迁移过来。

这场 Session 讲了什么

Session 介绍了 CloudKit 在 iOS 15 / macOS 12 中的多项改进。重点包括:

  1. 共享记录(Shared Records)的权限增强。开发者可以更细粒度地控制共享行为:只读/读写权限、自定义共享 UI、以及通过 CKShare 的权限层级(owner/participant)管理。
  2. CloudKit Console(Web 控制台)。全新的 Web 版管理工具,可以直接在浏览器中查看和操作 CloudKit 数据库,包括查询记录、修改 Schema、查看日志。不再依赖 CloudKit Dashboard 的旧版界面。
  3. 声明式 Schema 管理。通过 JSON 配置文件定义 Schema 变更,结合新的 cktool 命令行工具实现 Schema 的自动化部署,适合 CI/CD 流水线。
  4. 性能监控。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)
}

最佳实践

  1. 把 Schema JSON 文件纳入版本控制。声明式 Schema 的最大价值是可追溯,每次变更都有 commit 记录。如果 Schema 改坏了,可以精确回滚。
  2. 共享记录的 UI 要处理好权限冲突。当两个参与者同时编辑同一字段时,CloudKit 采用 last-write-wins 策略。对于关键数据,在 app 层实现乐观锁(Optimistic Locking)。
  3. 用 CloudKit Console 的监控面板定期检查 API 延迟。如果请求延迟超过 500ms,大概率是查询没有命中索引。去 Schema 配置中给常用查询字段添加索引。

还有什么值得关注

  • CloudKit Console 支持直接在浏览器中执行 CKQuery,方便调试数据问题。
  • CKDatabase 的 batch 操作现在支持原子提交(Atomic Zone),要么全部成功要么全部回滚。
  • CloudKit 的免费额度保持不变:每天 40 次请求/秒、每天 250MB 存储、每天 2GB 传输。
WWDC 2021