我有一个可在多个平台(macOS、iOS、iPadOS 等)上使用的应用程序,我的目标是在 CloudKit DB 更改时更新每个平台上的小部件,而无需打开该应用程序。例如,现在,如果您在 iOS 应用程序中更改了某些内容,则需要打开 macOS 应用程序,等待 iCloud 同步,然后 macOS 小部件才会反映新数据。
我使用指南创建了订阅。它似乎有效,当我的 AppDelegate 中的数据发生更改时,我会收到推送通知。
func application(
_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
if CKNotification(fromRemoteNotificationDictionary: userInfo) != nil {
...
let entries = container.viewContext.fetch(Entry.fetchRequest())
var result = ... // generate widget state from entries
...
UserDefaults.setValueForGroup(result, forKey: "widget_state")
WidgetCenter.shared.reloadAllTimelines()
} else {
completionHandler(.noData)
}
}
问题是,当我从
viewContext
获取数据时,我得到的是旧数据。如何获取新数据?
根据我的发现,我可以使用
CKFetchDatabaseChangesOperation
并以某种方式从远程数据库获取并应用所有更改,但它有一个庞大的实现,看起来像是重新发明轮子。
如果我启动应用程序,所有同步都会自动发生,如何在收到推送通知后强制执行相同的行为?还是我错过了什么?
目前尚不清楚您的记录区域订阅是如何配置的,但为了让您的应用程序能够在后台接收推送通知并更新数据,您需要将
shouldSendContentAvailable
设置为 true
。
具体操作方法如下:
let subscription = CKRecordZoneSubscription(zoneID: yourRecordZoneId,
subscriptionID: yourSubscriptionId)
let notificationInfo = CKSubscription.NotificationInfo()
notificationInfo.shouldSendContentAvailable = true
subscription.notificationInfo = notificationInfo
try await database.modifySubscriptions(saving: [subscription], deleting: [])
在上面的示例中,我使用 Swift 并发来更新订阅,但您也可以使用
CKModifySubscriptionsOperation
操作或 CKDatabase.save(_:completionHandler:)
函数
希望有帮助!