CloudKit 订阅未在 iOS10 上保存

Posted

技术标签:

【中文标题】CloudKit 订阅未在 iOS10 上保存【英文标题】:CloudKit subscriptions not saving on iOS10 【发布时间】:2016-08-27 13:02:47 【问题描述】:

我正在关注'CloudKit Best Practices' WWDC talk关于添加订阅的内容,ios10 中似乎有所改变。

下面的代码返回“成功!”,但我的“AllChanges”订阅从未出现在 CloudKit 仪表板的订阅类型中。

我正在使用 Xcode 8 beta 6。

    let subscription = CKDatabaseSubscription(subscriptionID:"AllChanges")
    let notificationInfo = CKNotificationInfo()
    notificationInfo.shouldSendContentAvailable = true
    subscription.notificationInfo = notificationInfo

    let operation = CKModifySubscriptionsOperation(subscriptionsToSave: [subscription], subscriptionIDsToDelete: [])
    operation.modifySubscriptionsCompletionBlock =  
        (modifiedSubscriptions: [CKSubscription]?, deletedSubscriptionIDs: [String]?, error: Error?) -> Void in

        if error != nil 
            print(error!.localizedDescription)
         else 
            print("Success!")
        
    
    operation.qualityOfService = .utility
    privateDatabase.add(operation)

【问题讨论】:

订阅有效吗?您是否尝试过使用 CKDatabase.fetchAllSubscriptions(completionHandler:) 获取您的 privateDatabase 中的所有订阅并查看它是否存在? privateDatabase.fetchAllSubscriptions (subscription: [CKSubscription]?, error: Error?) in print("Error = (error)") print("Subs = (subscription)") 1) 您是否尝试过在您的 modifySubscriptionsCompletionBlock 中打印 modifiedSubscriptions 的内容以确保它不为空? 2.) 您是否尝试过在 CloudKit Dashboard 中重置开发环境? 当我打印出 modifiedSubscriptions 时,里面有我的 AllChanges 订阅。我重置了开发环境,订阅仍然没有添加,虽然记录上传到 CloudKit 很好。 我看到与 Xcode 8 版本类似。我可以在私有数据库上创建没有问题的记录,但 CKModifySubscriptionsOperation 出现错误:()通知注册工作,用户被要求接受远程通知等。 【参考方案1】:

我在 CKDatabaseSubscription 上遇到过同样的问题,其他许多人也遇到过:

https://forums.developer.apple.com/thread/53546 https://forums.developer.apple.com/thread/61267 https://forums.developer.apple.com/thread/64071 https://forums.developer.apple.com/thread/63917

我先列出一些注意事项,以防他们解释您的问题:

订阅通常不会出现在“开发者”CloudKit 仪表板中(它们存在,但未显示 - 最简单的测试方法是重命名订阅并查看 CloudKit 是否抱怨重复订阅) 推送通知不会发送到模拟器

解决方案:

解决此问题的方法是创建一个自定义私有区域并将我的所有数据保存到该区域(仅适用于私有数据库)。然后我会收到关于该区域的任何更改的推送通知。

您将需要创建区域(-检查 CKAccountStatus = .available 和 -before- 任何记录保存):

let operation = CKModifyRecordZonesOperation(recordZonesToSave: [CKRecordZone(zoneName: "MyCustomZone")], recordZoneIDsToDelete: nil)
operation.modifyRecordZonesCompletionBlock =  (savedRecordZones: [CKRecordZone]?, deletedRecordZoneIDs: [CKRecordZoneID]?, error: Error?) in
    if let error = error 
        print("Error creating record zone \(error.localizedDescription)")
    

privateDatabase?.add(operation)

然后在保存记录时使用该区域:

let record = CKRecord(recordType: "MyRecordType", zoneID: CKRecordZone(zoneName: "MyCustomZone")) 
// you can save zone to CKRecordID instead, if you want a custom id

然后跳过 CKFetchDatabaseChangesOperation(因为我们已经知道我们的区域),并使用 CKFetchRecordZoneChangesOptions 代替:

let options = CKFetchRecordZoneChangesOptions()
options.previousServerChangeToken = myCachedChangeToken
let operation = CKFetchRecordZoneChangesOperation(
    recordZoneIDs: [myCustomZoneId],
    optionsByRecordZoneID: [myCustomZoneId: options]
)
operation.fetchAllChanges = true
operation.recordChangedBlock =  (record: CKRecord) -> Void in
        ... do something

operation.recordWithIDWasDeletedBlock =  (recordId: CKRecordID, recordType: String) -> Void in
        ... do something

operation.recordZoneFetchCompletionBlock =  (recordZoneId, changeToken, tokenData, isMoreComing, error) in
    if let error = error 
        print("Error recordZoneFetchCompletionBlock: \(error.localizedDescription)")
        return
    
    myCachedChangeToken = changeToken

privateDatabase?.add(operation)

【讨论】:

根据您在此处的回答,我从使用私有数据库的默认区域切换到自定义私有区域 - 并且修复了它。谢谢!我从未在文档中看到过这个限制。有人有参考吗? @vegashacker 自定义区域要求已记录在案,但很容易错过。 CloudKit Quick Start 表示“要使用 CloudKit 的更改跟踪功能,您需要将应用数据存储在用户私有数据库的自定义区域中”

以上是关于CloudKit 订阅未在 iOS10 上保存的主要内容,如果未能解决你的问题,请参考以下文章

CKAsset 未保存到 CloudKit - 保存所有其他字段

CloudKit“订阅重复”错误 - 获取 SubscriptionId

如何找出 CloudKit 订阅何时被删除?

如何更新 CloudKit 订阅

私有数据库和订阅的 Cloudkit 问题?

iOS 未收到来自 CloudKit 的推送通知