CloudKit 私有数据库为何无法将初始 schema 部署到生产环境?
结论
这条报错说明,TestFlight 应用访问的生产环境 schema 中没有 MyType,而生产环境不允许通过保存记录自动创建新的 record type。需要先在同一个 container 的开发环境中建立完整 schema,再部署到生产环境。Apple 的环境说明明确指出,TestFlight 使用生产环境。
开发环境能够读写,控制台却看不到类型和 custom zone,原因还无法仅凭现有信息确定。建议先核对 container、环境和 iCloud 账号,并确认“保存成功”的结果来自 CloudKit 服务端回调。
私有数据库也需要部署 schema
同一 container、同一环境中的各数据库共用 schema。开发环境支持通过代码保存 CKRecord,自动建立对应的 record type 和字段。因此,使用 private database 或 custom zone 时,也可以不在 Dashboard 手动创建类型。Apple 的数据库设计文档说明了这一机制。
需要分别检查 schema 和用户数据:
- schema 是否存在:在控制台的
Schema→Record Types中检查MyType和字段。 - 用户数据是否可见:在数据视图中选择
Private Database和对应的 zone。查看私有数据需要使用存储这些数据的同一个 iCloud 账号,不能通过团队管理权限查看任意用户的私有记录。Apple 的控制台说明列出了这一限制。
账号不同可以解释为什么看不到私有记录和 zone,但不能单独解释为什么 container 的 schema 中没有 MyType。
按顺序排查
1. 对齐应用和控制台的 container
检查应用实际使用的是 CKContainer.default(),还是显式指定的 CKContainer(identifier:)。将实际的 container identifier 与控制台顶部选中的 container 逐字比较,同时确认所属开发团队一致。
还要比较开发构建与 TestFlight 构建的 iCloud 配置,确认它们指向预期的同一个 container,不要仅凭项目名称判断。
2. 核对实际运行环境
在控制台选择 Development,再检查开发阶段创建的类型。应用使用哪个环境由签名配置中的 com.apple.developer.icloud-container-environment 决定,其值为 Development 或 Production。应检查实际构建产物的配置。Apple 的 entitlement 定义说明了这两个取值。
仅从 Xcode 启动应用,不能证明当前构建一定访问开发环境。
3. 确认保存确实到达 CloudKit
创建 CKRecord 对象、写入本地缓存或立即从本地读取,都不足以证明远端 schema 已建立。检查保存操作的完成回调并记录完整错误;如果使用批量操作,还要检查逐条记录的失败信息。
如果已确认在同一个 container 的开发环境中成功保存了 MyType,控制台的 Record Types 应能看到该类型。如果仍然为空,需要继续检查控制台选择、请求日志和实际保存路径,不能直接认定为 CloudKit 不支持私有数据库 schema 部署。
用最小示例验证开发环境写入
以下示例适用于直接使用 CloudKit 且支持 Swift 并发 API 的项目。请替换 container identifier、zone 名称及字段,确认使用开发环境后再执行。示例会创建测试 zone 和记录。
import CloudKit
func createDevelopmentSample() async throws {
let container = CKContainer(identifier: "iCloud.com.example.MyApp")
let database = container.privateCloudDatabase
let zone = CKRecordZone(zoneName: "MyCustomZone")
let savedZone = try await database.save(zone)
let recordID = CKRecord.ID(
recordName: UUID().uuidString,
zoneID: savedZone.zoneID
)
let record = CKRecord(recordType: "MyType", recordID: recordID)
record["name"] = "Schema test" as CKRecordValue
let savedRecord = try await database.save(record)
print("Saved to CloudKit:", savedRecord.recordID)
}
调用方需要处理抛出的错误。保存成功返回后,再到控制台确认结果。示例只写入了 name 字段;实际应用还需要将所有待部署字段以正确类型写入开发环境,或在控制台补齐,不能假定未赋值的字段已经建立。
部署并验证生产环境
确认开发环境的 Record Types 中存在 MyType 和所需字段后:
- 在 CloudKit Console 中打开
CloudKit Database,选择正确的 container。 - 选择
Deploy Schema Changes,检查待部署的类型、字段和索引,再执行部署。 - 切换到
Production,确认MyType和所需字段已经存在。 - 重新通过 TestFlight 执行保存操作,检查服务端返回结果。
部署需要具备编辑生产环境的权限。部署复制的是 schema,不会复制开发环境的记录。Apple 的 schema 部署指南给出了具体流程。
生产环境中的 custom zone 也应由应用针对当前用户创建或确认存在;schema 部署不会迁移用户数据和 zone。
如果仍提示“没有检测到变更”,就回头核对 container 和环境:当前选中的开发 schema 是否真的存在 MyType?如果生产 schema 已有该类型,而 TestFlight 仍报告缺失,应重点比较 TestFlight 实际访问的 container,并检查记录类型名称的拼写和大小写。
注意事项
生产 schema 部署后,应通过新增类型和字段继续演进,不能依赖删除或重命名已有类型、字段来修复问题。每次新增 record type 或字段,都应先在开发环境验证,再部署到生产环境。
当前错误已明确指向生产 schema 缺少类型,无需为了建立 schema 将私有数据改存到 public database。
备注:内容仅供参考。
