【问题标题】:How to subscribe to changes for a public database in CloudKit?如何订阅 CloudKit 中公共数据库的更改?
【发布时间】:2018-11-06 19:40:11
【问题描述】:

在 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)
            }
        })
    }
}

【问题讨论】:

  • 我不是那种只会去stackoverflow随便问一个问题的人。我已经对 stackoverflow 和其他网站进行了适当的研究,并且还阅读了 iBook 中关于 IOS12 swift 开发的 CloudKit 部分。到现在还没有任何结果。
  • 一个问题。是否有可能订阅公共数据库的通知?;)这仅适用于私有和共享,但不适用于公共。我说的对吗?

标签: ios swift database cloudkit


【解决方案1】:

您可以检查以下几项其他事项:

= 1 =

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

= 2 =

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

= 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 中重新构建。

祝你好运! :)

【讨论】:

  • 谢谢!!这对我有用。我使用的是 iPhone 模拟器(第 4 点),在我使用真正的 iPhone 后,它开始接收通知。非常感谢!
  • @PetervanLeeuwen:嗨,彼得。我正在尝试做几乎与您在问题中描述的完全相同的事情。您能否指出任何有助于您了解如何设置和订阅 CloudKit 通知的书籍、文章或链接?目前,我已经能够在一台设备上的公共 CloudKit 上的一个简单列表中成功保存、编辑和删除数据。但是我在一台设备上所做的任何更改都不会在另一台设备上自动刷新,直到我重新启动应用程序或手动创建刷新按钮。如果您能指出帮助您解决问题的资源,我将不胜感激。谢谢。
【解决方案2】:

我正在使用RxCloudKit 库,这是一个关于它如何处理查询通知的代码 sn-p -

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>

【讨论】:

  • 我更新了我的问题,以便您了解我目前的状态。我已经尝试过你建议的方法。
  • Info.plist 怎么样?是否包括 UIBackgroundModesfetchremote-notification
  • 它确实包含这些值
  • 用创建订阅的同一个账号登录后,能否在CloudKit仪表板看到查询订阅?
  • 是的,订阅在那里。
【解决方案3】:

更新:正如 Reinhard 在他的评论中提到的:实际上,您仍然可以从公共数据库订阅更改并手动将更改导入 Core Data。如果 Apple 特别提到了这些差异,我仍然不确定依赖公共数据库中的订阅是否是个好主意

原答案:

我认为接受的答案不能完全回答这里的问题。 简短的回答是 CloudKit 公共数据库不支持私有数据库等订阅。相反,只能使用轮询机制。 NSPersistentCloudKitContainer 会自动处理这个问题,但很少更新。

WWDC2020 的这篇演讲详细解释了这一点,我建议您观看它,因为还有其他重要细节提到了公共数据库与私有数据库的不同之处:https://developer.apple.com/wwdc20/10650

在谈话中,他们提到在每次应用启动时以及应用使用大约 30 分钟后都会启动一次拉取。

【讨论】:

  • 感谢您的评论! :)
  • 是的,只是偶然发现了您遇到的相同问题,并在这里浪费了数小时的故障排除时间。它可能不再对您有帮助,但也许对其他人没有帮助;)
  • 抱歉,您不正确:CloudKit 公共数据库确实支持订阅。在您引用的 WWDC 视频中,他们说本地 CoreData 数据库是通过轮询更新的。他们没有说的是您可以另外订阅公共 iCloud 数据库中的更改,更改后您将收到推送通知。然后由您使用推送的信息更新 CoreData。我在我的应用程序中执行此操作,它可以正常工作。
  • 非常有趣,谢谢,我不知道。虽然我不确定如果他们在谈话中明确提及差异,这种行为是否会保持这种状态并在未来继续发挥作用。
  • 其实他们说CoreData+CloudKit和公共数据库不使用推送通知,而是在iCloud发生变化时轮询更新CoreData。原因可能是无需登录 iCloud 即可读取公共数据。但是如果你登录了,你可以写订阅记录,并在更改后收到推送通知。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-12
  • 1970-01-01
  • 2014-10-25
  • 1970-01-01
相关资源
最近更新 更多