Как подписаться на изменения для публичной базы данных в CloudKit? - PullRequest
0 голосов
/ 06 ноября 2018

Каков наилучший способ подписаться на публичную базу данных в CloudKit? У меня есть стол с персонами. Каждый человек содержит имя и местоположение. После изменения местоположения оно обновляется в CloudKit. Эта часть работает нормально.

Но я не могу заставить его работать, чтобы получать уведомления при обновлении записи.

Некоторый пример был бы очень полезен, поскольку я уже рассмотрел возможный вариант. Я рассмотрел варианты сохранения подписки в базе данных, а также параметр CKModifySubscriptionOperation.

В настоящее время мой код для подписки выглядит следующим образом:

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

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Вот еще несколько вещей, которые вы можете проверить:

= 1 =

Убедитесь, что контейнер CloudKit, определенный в вашем коде, является тем же, к которому вы обращаетесь на панели мониторинга CloudKit. Иногда мы пропускаем то, что выбрали в Xcode как контейнер CloudKit, когда создаем и тестируем несколько контейнеров.

= 2 =

Проверьте вкладку Подписки на панели инструментов CloudKit и убедитесь, что ваша подписка Person создается при запуске приложения. Если вы видите это, попробуйте удалить его в CK Dashboard, а затем снова запустите ваше приложение и убедитесь, что оно снова появляется.

= 3 =

Проверьте журналы в CK Dashboard. Они будут показывать запись в журнале типа push всякий раз, когда отправляется push-уведомление. Если он регистрирует это при обновлении / добавлении записи в CK Dashboard, то вы знаете, что проблема связана с вашим устройством.

= 4 =

Помните, что push-уведомления не работают в симуляторе iOS. Вам нужно реальное устройство (или Mac, если вы создаете приложение macOS).

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

Удачи! :)

0 голосов
/ 07 ноября 2018

Я использую библиотеку 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()        
...

UPDATE: Info.plist должно содержать следующее -

<key>UIBackgroundModes</key>
<array>
  <string>fetch</string>
  <string>remote-notification</string>
</array>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...