Как получать уведомления Cloudkit об изменениях, внесенных в записи поделился со мной?

У меня есть две учетные записи icloud (A и B) на двух разных устройствах. От одного из них (A) я делюсь ckrecord с другим (B) следующим образом:

let controller = UICloudSharingController { controller, preparationCompletionHandler in

    let share = CKShare(rootRecord: record)
    share[CKShareTitleKey] = "title" as CKRecordValue

    share[CKShareTypeKey] = "pl.blueworld.fieldservice" as CKRecordValue
    share.publicPermission = .readWrite

    let modifyOperation = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: nil)
    modifyOperation.savePolicy = .ifServerRecordUnchanged
    modifyOperation.perRecordCompletionBlock = { record, error in
        print(error?.localizedDescription ?? "")
    }

    modifyOperation.modifyRecordsCompletionBlock = { records, recordIds, error in

        print(share.url)
        preparationCompletionHandler(share, CloudAssistant.shared.container, error)
    }

    CloudAssistant.shared.container.privateCloudDatabase.add(modifyOperation)
}

controller.delegate = self

UIViewController.top()?.present(controller, animated: true)

Когда второе устройство (B) приняло общий доступ к cloudkit, я получаю запись и подписываюсь на изменения:

func application(_ application: UIApplication, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShareMetadata) {

    let acceptSharesOperation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata])
    acceptSharesOperation.perShareCompletionBlock = { metadata, share, error in

        if let error = error {
            UIAlertController.show(withMessage: error.localizedDescription)
        } else {

            let operation = CKFetchRecordsOperation(recordIDs: [cloudKitShareMetadata.rootRecordID])
            operation.perRecordCompletionBlock = { record, _, error in

                if let error = error {
                    UIAlertController.show(withMessage: error.localizedDescription)
                } else if let record = record {
                    CloudAssistant.shared.save(records: [record], recordIDsToDelete: [])

                    let options: CKQuerySubscriptionOptions = [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion]
                    let territorySubscription = CKQuerySubscription(recordType: "Territory", predicate: NSPredicate(value: true), options: options)

                    let notificationInfo = CKNotificationInfo()
                    notificationInfo.shouldBadge = false
                    notificationInfo.shouldSendContentAvailable = true

                    territorySubscription.notificationInfo = notificationInfo

                    CloudAssistant.shared.sharedDatabase?.save(territorySubscription) { _, _ in }
                }
            }

            CloudAssistant.shared.container.sharedCloudDatabase.add(operation)
        }
    }
    acceptSharesOperation.qualityOfService = .userInteractive
    CKContainer(identifier: cloudKitShareMetadata.containerIdentifier).add(acceptSharesOperation)
}

Теперь с устройства А я успешно (я уверен в этом, изменения сохранены в iCloud) выполняю обновление записи, которой делятся с другими. Но устройство B не знает об этом, если я не получу запись вручную еще раз.

Но с другой стороны, это работает довольно хорошо.

Если я успешно выполню обновление записи, которой поделились со мной (на устройстве B), тогда устройство A mnagically получит уведомление об изменении, и все в порядке. В чем разница?

Как подписаться на изменения в записях, которыми поделились со мной?

PS, когда я смогу, я начну ставку 200 или даже больше для того, кто поможет мне в этом.

iOS 11, Swift 4, Xcode 9

1 ответ

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

  1. Убедитесь, что приложение зарегистрировано для уведомлений
  2. Убедитесь, что на устройстве включены уведомления для этого приложения
  3. Убедитесь, что все устройства используют один и тот же контейнер
  4. При следующем запуске приложения прочитайте все подписки, используя fetchAllSubscriptionsWithCompletionHandler и NSLog детализирует каждую подпрограмму (особенно: subscriptionID, параметры триггера, тип записи и предикат). Убедитесь, что ожидаемые подводные лодки существуют. Убедитесь, что предикат каждого подчиненного элемента соответствует ожиданиям (в этом случае сравните предикаты, которые вы найдете на обоих устройствах).

Я потратил кучу времени на отладку "отсутствующих" уведомлений, когда:

  1. Моя локально построенная версия использовала среду TEST, а пользователи TestFlight получали доступ к среде PROD. Шаг 2 отладки нашел это.
  2. При непреднамеренном повторном использовании идентификатора подписки, таким образом, каждая новая подпрограмма перезаписывает предыдущую. Шаг 4 отладки в конечном итоге выявил проблему

До сих пор эти четыре шага отладки помогли мне понять все мои проблемы с "отсутствующим уведомлением". Однажды я понял, почему уведомления не появляются, это сузило, какой блок кода был ответственным.

Другие вопросы по тегам