2
votes

Push notifications are not being sent (or received) to my app which is using CloudKit subscriptions, as there are a lot of ways this can go south, I'm going to list below what I've done, which may help others having the same issue, and (hopefully) will point out what I'm doing wrong :(

Specifically, I'm trying to get a silent notification on record insertion (both in the background in the foreground) and I am getting neither.

Project settings I enable CloudKit under capabilities, setup the record type in Dashboard. I enable push notifications for the app under capabilities. And I enable background modes "remote-notification".

Register for remote notifications on launch:

    // Register for push notification
    let settings = UIUserNotificationSettings(forTypes: [.Alert,.Badge,.Sound], categories: nil)
    application.registerUserNotificationSettings(settings)

    // Register for remote notification
    application.registerForRemoteNotifications()

Listen for push notification registration success (Succeeds) and create subscription:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    NSLog("Remote notifications registered - %@",deviceToken)
    createSubscriptions()
}

Create my subscription object, and setup it's notification info, and save it to the server:

private func createSubscriptions(user : CKRecord, completion: (NSError?) -> ()) {
        let messageSubscription = CKSubscription(recordType: "Messages", predicate: NSPredicate(format:"TRUEPREDICATE"), subscriptionID: "Messages", options: .FiresOnRecordCreation)
        let notificationInfo = CKNotificationInfo()
        notificationInfo.shouldSendContentAvailable = true
        notificationInfo.soundName = ""
        messageSubscription.notificationInfo = notificationInfo
        CKContainer.defaultContainer().publicCloudDatabase.saveSubscription(subscription) { (_, error) in
            if let error = error {
                if error.domain == "CKErrorDomain" && error.code == 15 {
                    NSLog("Already set, ignoring dupe")
                }
                else
                {
                    completion(error)
                    return
                }
            }
            completion(nil)
        }
}

I can see in CloudKit Dashboard that the subscription does get created successfully.

I then create some records ("Message") from a second device or the dashboard, see that they are added either in query or dashboard calls, but the method I have to get the notification is never called:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    // Crickets.  Never called
}

I understand notifications don't work on simulator. I've tried this in dev using a device, and in production using testflight and a number of devices. Am I missing osmething obvious?

2

2 Answers

2
votes

You seem to be doing everything right. Two things I can think of:

  1. Are you sure you are registering for remote notifications? I can't see the call to application.registerForRemoteNotifications() anywhere. I am assuming you forgot to paste it here.

  2. Have you tried to delete the subscription in the panel and recreate it? I have had issues where registering the same subscription multiple times with different notificationInfo would break it and it would stop firing.

1
votes

This works ... and is a little different from your version... I don't try and register for specific notifications, I register for all... and then look at them more closely after I have received them.

func application(application: UIApplication, didFinishLaunchingWithOptions    launchOptions: [NSObject: AnyObject]?) -> Bool {

    application.registerForRemoteNotifications()
    return true
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    let notification = CKQueryNotification(fromRemoteNotificationDictionary: userInfo as! [String : NSObject])


    if notification.notificationType == .Query {
        let queryNotification = notification
        if queryNotification.queryNotificationReason  == .RecordUpdated {
           print("queryNotification.recordID \(queryNotification.recordID)")
        }
    }
   }