CloudKit CKSubscription without notifications?
Asked Answered
D

2

12

I'm writing a Swift app with CloudKit. When a record is modified in CloudKit by a device, I want the corresponding records to be updated in the local storage of the other devices without displaying a push notification.

Do I need to call registerUserNotificationSettings in didFinishLaunchingWithOptions (meaning that the user has to accept the notifications for my app) even if I don't plan to display any push notification?

application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert, categories: nil))
Damick answered 26/11, 2015 at 9:5 Comment(0)
C
3

Yes you do need to call registerUserNotificationSettings even all you need is background remote notification. So user will be prompt for notifications permission. It makes no sense as users will not be seeing the notifications but that's how it is.

I use this to set it up:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { let settings = UIUserNotificationSettings(forTypes: .None , categories: nil) application.registerUserNotificationSettings(settings) application.registerForRemoteNotifications() }

Make sure when you call CloudKit saveSubscription you provide shouldSendContentAvailable = true. The following code is for subscription for a custom zone:

let subscription = CKSubscription(zoneID:zoneID, options: CKSubscriptionOptions(rawValue: 0))

let notificationInfo = CKNotificationInfo()
notificationInfo.shouldSendContentAvailable = true

subscription.notificationInfo = notificationInfo

CKContainer.defaultContainer().privateCloudDatabase.saveSubscription(subscription) { subscription, error in
}

You also need to enable Background Modes capability under Xcode for your project, and tick the box Remote Notifications.

User can go to Settings app to disable notifications for your app. But you will still receive remote notification trigger by CloudKit server.

Implement the following functions in your AppDelegate to receive remote notifications:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {}

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {}
Concussion answered 27/11, 2015 at 8:31 Comment(1)
Leaving this out tripped me up from didReceiveRemoteNotification being triggered even though the push was coming from CloudKit. notificationInfo.shouldSendContentAvailable = true But once added, worked like a charm for my silent notification!Cuckoo
V
17

In this case you do not need to call registerUserNotificationSettings.

You need to add the Info.plist setting "Required background mode" (UIBackgroundModes), "App downloads content in response to push notifications" (remote-notification). And also call registerForRemoteNotifications. Finally, set notificationInfo.shouldSendContentAvailable = YES; on your subscription.

Now since your app is being run to respond to all notifications you need to be careful to handle the case where a notification is missed, you can use airplane mode to test that, only the last is delivered.

Note, once you have created your subscription from any device, application:didReceiveRemoteNotification:fetchCompletionHandler: will be called on all devices that are using the same iCloud account and have the app installed.

Vichy answered 11/2, 2016 at 0:36 Comment(2)
This is the correct answer. No prompt to user to allow Push Notifications but still gets the notifications which need to be handled by AppDelegate but the callback is -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler. The callback mentioned above in the answer is wrong but might be because this is a really old answer.Phenazine
If one does not want to be notified when app is in background and not show the alert either then one need not add the UIBackgroundModes and associated sub-key remote-notification. In this case app gets the notification in the usual remote notification handler in AppDelegate but still without the user acceptance prompt for enabling push notifications. So there are two ways depending on the need. So basically not calling registerUserNotificationSettings works for the special case of CloudKit notifications.Phenazine
C
3

Yes you do need to call registerUserNotificationSettings even all you need is background remote notification. So user will be prompt for notifications permission. It makes no sense as users will not be seeing the notifications but that's how it is.

I use this to set it up:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { let settings = UIUserNotificationSettings(forTypes: .None , categories: nil) application.registerUserNotificationSettings(settings) application.registerForRemoteNotifications() }

Make sure when you call CloudKit saveSubscription you provide shouldSendContentAvailable = true. The following code is for subscription for a custom zone:

let subscription = CKSubscription(zoneID:zoneID, options: CKSubscriptionOptions(rawValue: 0))

let notificationInfo = CKNotificationInfo()
notificationInfo.shouldSendContentAvailable = true

subscription.notificationInfo = notificationInfo

CKContainer.defaultContainer().privateCloudDatabase.saveSubscription(subscription) { subscription, error in
}

You also need to enable Background Modes capability under Xcode for your project, and tick the box Remote Notifications.

User can go to Settings app to disable notifications for your app. But you will still receive remote notification trigger by CloudKit server.

Implement the following functions in your AppDelegate to receive remote notifications:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {}

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {}
Concussion answered 27/11, 2015 at 8:31 Comment(1)
Leaving this out tripped me up from didReceiveRemoteNotification being triggered even though the push was coming from CloudKit. notificationInfo.shouldSendContentAvailable = true But once added, worked like a charm for my silent notification!Cuckoo

© 2022 - 2024 — McMap. All rights reserved.