在CloudKit中订阅公共数据库的最佳方法是什么? 我有一张桌子。每个人都有一个名字和一个位置。 位置更改后,将在CloudKit中更新位置。 那部分工作正常。
但是当记录更新时,我无法使其获得通知。
因为我已经研究了可能的选项,所以某些示例将非常有帮助。 我已经研究了将预订保存在数据库中的选项以及CKModifySubscriptionsOperation选项。
当前,我要订阅的代码如下:
let predicate = NSPredicate(format: "TRUEPREDICATE")
let newSubscription = CKQuerySubscription(recordType: "Person", predicate: predicate, options: [.firesOnRecordCreation, .firesOnRecordDeletion, .firesOnRecordUpdate])
let info = CKSubscription.NotificationInfo()
info.shouldSendContentAvailable = true
newSubscription.notificationInfo = info
database.save(newSubscription, completionHandler: {
(subscription, error) in
if error != nil {
print("Error Creating Subscription")
print(error)
} else {
userSettings.set(true, forKey: "subscriptionSaved")
}
})
有人可以告诉我我的AppDelegate看起来如何吗?
我已将didReceiveRemoteNotification函数添加到我的AppDelegate中。我也叫application.registerForRemoteNotifications()。这是我的didReceiveRemoteNotification函数的样子: 印刷品甚至不适合我。
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print("Notification!!")
let notification = CKNotification(fromRemoteNotificationDictionary: userInfo) as? CKDatabaseNotification
if notification != nil {
AppData.checkUpdates(finishClosure: {(result) in
OperationQueue.main.addOperation {
completionHandler(result)
}
})
}
}
答案 0 :(得分:1)
我正在使用RxCloudKit库,这是它如何处理查询通知的代码段-
public func applicationDidReceiveRemoteNotification(userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let dict = userInfo as! [String: NSObject]
let notification = CKNotification(fromRemoteNotificationDictionary: dict)
switch notification.notificationType {
case CKNotificationType.query:
let queryNotification = notification as! CKQueryNotification
self.delegate.query(notification: queryNotification, fetchCompletionHandler: completionHandler)
...
此方法从func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
调用
在您收到通知之前,您需要执行以下操作-
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
application.registerForRemoteNotifications()
...
更新:
Info.plist
应包含以下内容-
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
答案 1 :(得分:1)
您还可以检查以下几件事:
= 1 =
确保代码中定义的CloudKit容器与您在CloudKit仪表板中访问的容器相同。有时,当我们创建和测试多个容器时,会忽略在Xcode中选择的CloudKit容器。
= 2 =
检查CloudKit仪表板中的 Subscriptions 标签,并确保在启动应用程序时正在创建Person
订阅。如果看到它,请尝试在CK仪表板中将其删除,然后再次运行您的应用程序,并确保它再次出现。
= 3 =
在CK仪表盘中检查日志。每当发送推送通知时,它们将显示类型为push
的日志条目。如果您在CK仪表盘中更新/添加记录时正在记录它,那么您就知道问题出在设备上。
= 4 =
请记住,推送通知在iOS模拟器中不起作用。您需要一台实际的设备(如果正在制作macOS应用,则需要一台Mac)。
= 5 =
通过广泛的测试,我发现,即使您始终设置alertBody
,即使它为空,通知也更可靠。像这样:
let info = CKSubscription.NotificationInfo()
info.shouldSendContentAvailable = true
info.alertBody = "" //This needs to be set or pushes don't always get sent
subscription.notificationInfo = info
= 6 =
对于iOS应用,我的应用委托处理如下通知:
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//Ask Permission for Notifications
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { authorized, error in
DispatchQueue.main.async {
if authorized {
UIApplication.shared.registerForRemoteNotifications()
}
}
})
return true
}
//MARK: Background & Push Notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]{
let dict = userInfo as! [String: NSObject]
let notification = CKNotification(fromRemoteNotificationDictionary: dict)
if let sub = notification.subscriptionID{
print("iOS Notification: \(sub)")
}
}
//After we get permission, register the user push notifications
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//Add your CloudKit subscriptions here...
}
}
如果仅执行后台推送,则不需要获得通知许可,但是对于用户以弹出式通知形式看到的任何内容,必须获得许可。如果您的应用程序不要求该许可,请尝试将其从设备上删除,然后再次使用Xcode构建。
祝你好运! :)
答案 2 :(得分:0)
更新:正如Reinhard在他的评论中所述:实际上,您仍然可以从公共数据库中订阅更改,并将更改手动导入到Core Data中。我仍然不确定如果苹果特别提到了这些差异,那么依靠公共数据库中的订阅是否是一个好主意
原始答案:
我认为接受的答案不能完全回答这里的问题。
简短的答案是,CloudKit公共数据库不像私有数据库那样支持订阅。相反,只能使用轮询机制。 NSPersistentCloudKitContainer
自动处理此问题,但很少更新。
WWDC2020上的这次演讲详细解释了这一点,我建议您观看,因为其中提到了其他重要细节,其中公共数据库与私有数据库不同:https://developer.apple.com/wwdc20/10650
在谈话中,他们提到在每次启动应用程序后以及大约30分钟的应用程序使用后都会启动一次拉动。