CKSubscription and Who Receives Notifications

Maybe I'm missing something. CloudKit offers a number of choices on how to define subscriptions and the notification data contained. However there seems to be no direct way to set which users actually receive them. It appears that its an all or nothing situation.


Using the Apple art work example, suppose the app has 1000 users. Only one wants to be notified when new art by Me Chen is added. So another user, of the 1000, adds a Me Chen art piece. The subscription fires and all other 998 users get the notice as well.


Somehow this doesnt seem to be the desired result.

Replies

Subscriptions are regostered on an iCloud Account - by - iCloud Account basis. When I register a subscription my iPhone and my iPad both get notified when a change is made but no one else's device gets the notification. And if the change was made by my iPad then only my iPhone will get the notification.

Thats not what I am seeing here. As a test, I have 4 different IOS devices. An iPhone 5,6 and iPad Mini are on one iCloud account. An additional iPhone 5S is on a different iCloud account. Subscriptions from any of those devices flow to the other devices, regardless of account.


Subscriptions on a private database work the way you outlined. Subscriptions on a public database appear to be global and seem to be received by all devices using the app, regardless of iCloud account.

So I tested it and it worked as I expected it to. In my hands, in the Development environment, subscriptions flow only to the devices on the iCloud Account that registered the subscription. I had to be sure I deleted all of the incorrect subscriptions in the current iCloudAccount that were left over from my earlier attempts at this:


(in the code below, currentSubscriptionIDs are all the subscriptions.subscriptionID returned by a fetchAllSubscriptionsWithCompletionHandler: but, if the subscription I wanted to add was already there, removing it from that the currentSubscriptiuonIDs and making subscriptionToAdd=nil so I don't delete it or add it in a second time.)


     CKModifySubscriptionsOperation *modifySubscriptions=
            [[CKModifySubscriptionsOperation alloc] initWithSubscriptionsToSave:subscriptionToAdd 
                  subscriptionIDsToDelete:currentSubscriptionIDs];

I believe that is the case for only subscriptions on the private database. My testing shows subsciptions on the public database bridge iCloud accounts and appear to go to all devices with the app (actually all devices that have some iCloud account signed in). I have tested this many times on many devices and accounts and public subscriptions appear on all.


If they didnt, then that would make the public database someless useful to say the least.

I am talking about the public database. It works for me. I have one device and I switch its iCloud Account. I get the notifications when logged into one iCloud Account and I do not get the notifications when logged into the other iCloud Account, just as I expect.


Check your subscriptions and verify that you have not left a subscription in the iCloud Account in which you do not want a notification.

Already did that. They still occur just like I outlined. If you do a subscriptions list, its always the same on each device regardless of account. They are public. There is clearly some confusion here somehow, not yet sure why. Apple docs are light in this area/

As far as I can tell, iCloud acccounts only matter when trying to write to a public database. An app can always read. Subscriptions are written, so a user would need to be logged into some iCloud account to create any.


Still trying to determine the logic for which devices. Ideally it would only be those that subscribe to a specific record type option.

I am seeing different data today on who receives what.

This is what seems to be with CloudKit subscriptions. As you said, they are stored at the iCloud account level. So if a user has 5 devices, a subscription created on one applies to all 5.


Only users with a currently logged in iCloud account can create a subscription on a public database. That subscription will fire on record changes (based on option for create, delete and/or modify) from any user on any iCloud account anywhere.


Public database info can be accessed/read by any user, regardless of whether they have a currently logged on iCloud account for the device. They can only write to the public database if they are currently logged on iCloud account.


A user with no current iCloud account connected can still query and fetch data from the public database. They just can’t write.


If a user has 5 devices on the same iCloud account, and only wants CloudKit record change notifications to come to a subset of those devices, that wont work. It’s all or nothing for subscriptions within a single iCloud account. That would require other cloud technologies or other totally separate API areas.

What you wrote is all well documented in:

https://developer.apple.com/library/prerelease/ios/documentation/DataManagement/Conceptual/CloudKitQuickStart/EnablingiCloudandConfiguringCloudKit/EnablingiCloudandConfiguringCloudKit.html#//apple_ref/doc/uid/TP40014987-CH2-SW1

"An app has access to both a public and private database in each container. The public database is for storing user and app data that is shared between all instances of the app. By default, all users can read the public database, but they need to enter iCloud credentials to write to the public database. There’s a private database for each user of your app, but the app only has access to the private database of the current user. The user has to enter iCloud credentials for the app to read and write to the private database."

Other than that, the key question you asked was regarding subscriptions "......there seems to be no direct way to set which users actually receive them."

You are now confirming my original post above:

"Subscriptions are regostered(sic) on an iCloud Account - by - iCloud Account basis. When I register a subscription my iPhone and my iPad both get notified when a change is made but no one else's device gets the notification. And if the change was made by my iPad then only my iPhone will get the notification."


Regarding your desire to limit the notificatications to a subset of devices logged into the same iCloud Account - the user can go to Settings>The App>Notifications>Allow Notifications and turn that off (or limit the types of notifications). You can do that programmatically using:

[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];

[[UIApplication sharedApplication] registerForRemoteNotifications];

Turning off notications for some apps is not an option, as notifications may be used for dozens of cases. Turning them off is an all or nothing choice. In these cases, other API use or approachs works much better.


Appreciate all the comments, as the device focus was not obvious given the current docs.

Here's the overall structure for subscriptions:


Cloud - an iCloud Account - a device

- another device under the same iCloud Account

- another iCloud Account


The Cloud interacts with the iCloud Account. Subscriptions are specific to the iCloud Account under which the subscription was registered. All devices under the same iCloud Account are treated equally by the Cloud. Each device can adjust itself so it responds differently to things thrown at it by the Cloud. But a device can't do that when the App is not in the foreground (e.g. setting the badge on the App Icon and the display of a notification and the beepy noise).

  • Can't you use a UNNotificationServiceExtension to adjust and even ignore the notification when the App is not in f the foreground?

Add a Comment

Background works just fine too for notifications, as each gets some seconds to process the data. Silent notifications, which are supported, make it easier still.