如何订阅 CloudKit 中公共数据库的更改?

Pet*_*wen 6 database ios swift cloudkit

在 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")
      }
})
Run Code Online (Sandbox Code Playgroud)

有人也可以告诉我我的 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)
            }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

Cli*_*rum 4

您可以检查以下一些其他事项:

= 1 =

确保代码中定义的 CloudKit 容器与您在 CloudKit 仪表板中访问的容器相同。有时,当我们创建和测试多个容器时,我们会忽略在 Xcode 中选择的 CloudKit 容器。

= 2 =

检查CloudKit 仪表板中的“订阅”选项卡,并确保Person在启动应用程序时正在创建您的订阅。如果您看到它,请尝试在 CK Dashboard 中删除它,然后再次运行您的应用程序并确保它再次显示。

= 3 =

检查 CK 仪表板中的日志。push每当发送推送通知时,它们都会显示类型的日志条目。如果当您在 CK Dashboard 中更新/添加记录时记录它,那么您就知道问题出在您的设备上。

= 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
Run Code Online (Sandbox Code Playgroud)

= 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...
  }

}
Run Code Online (Sandbox Code Playgroud)

如果您只进行后台推送,则不需要获得通知权限,但对于用户以弹出通知形式看到的任何内容,您必须获得权限。如果您的应用程序没有请求该权限,请尝试将其从设备上删除并在 Xcode 中重新构建。

祝你好运!:)