Are public database subscription notifications received by all users with the same subscription? - cloudkit

I have set up a CKSubscription* so that I receive changes to a record type.
I'm using the public database.
When I test with the same user (same iCloud account) I receive the notification.
If I use a different user (different iCloud account) I don't receive the notification.
Are subscriptions designed to only work between devices of the same user?
Here is the documentation that describes subscriptions:
Use a CKSubscription object to track changes occurring on the server.
A subscription acts like a persistent query on the server that can
track the creation, deletion, and modification of records. When
changes occur, they trigger the delivery of push notifications so that
your app can respond appropriately.
https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CKSubscription_class/index.html#//apple_ref/occ/cl/CKSubscription
I would expect to receive a notification no matter which user edits the record, and subscription predicate should still match.
UPDATE
*Every user has a subscription with the same predicate, essentially focused on a single recordType with a particular property value.
The payload for this subscription is only to push shouldSendContentAvailable=YES.
The documentation reads:
When this property is YES, the server includes the content-available
flag in the push notification’s payload. That flag causes the system
to wake or launch an app that is not currently running. The app is
then given background execution time to download any data related to
the push notification, such as the set of records that changed. If the
app is already running in the foreground, the inclusion of this flag
has no additional effect and the notification is delivered to the app
delegate for processing as usual.
The recordType's security permission is:
FURTHER UPDATE
Checked the logs of the device not receiving the push when it should and saw:
apsd[85]: Silent Push: Deny app not available
Rebooted the device and now it works fine!

This behaviour was due to a mistake in how my CKSubscription was configured. If we want all users to receive notifications from the subscription then it should not have a zoneID set (should remain nil). I was setting the zoneID to the value from the defaultRecordZone, this will restrict the notifications to the current user only as the defaultRecordZone's user is the current user.
UPDATE
Finally solved the problem. Not only was it an issue of zoneID, but there also seems to be a bug. My subscription notificationInfo simply had shouldSendContentAvailable set to YES. This doesn't cause the subscription notification to fire for changes made by anyone other than the current user (u1d1->u1d2, but not u1d1>u2d2). I simply added an alertBody and the notifications start firing.
Anyone else face this issue?
UPDATE 2
Rebooting the device solved the issue.

And to add another dimension to the answers above, CKSubscriptions are logged 'per iCloud Account' not per device. All devices logged into the same iCloud Account (*) will receive all notifications based on any subscription entered by any device under that iCloud Account. When the above refers to 'user' they mean 'any device logged into that iCloud Account'.
except for the particular device that modified the file leading to the notification

Every user should create it's own subscription. A subscription is only valid for the user that created it. On app startup you should test if the subscriptions are there for the current user (you could use the database.fetchAllSubscriptionsWithCompletionHandler function for that)
Then if there is a subscription for a recordType and predicate, then that user should receive the notifications of there are any changes for records within this recorType and predicate.
There is no guarantee that every change will be pushed. If there are multiple notifications, it could happen that you won't receive all. This is why after receiving a notification you should also query for outstanding subscription notifications on the server (using CKFetchNotificationChangesOperation)
If you create a record on your device, then you should not receive a notification for that on that device. So if you have a data colleciont for a subscription in your app, then you should also update this after you modified the data.
If you think this is complex, then you could try EVCloudKitDao

Related

How to detect Realm app user has been deleted?

app.currentUser.delete deletes the Realm app user from the server side. However, it seems on other logged-in devices, and the data upload is still working with no auth error.
On other logged-in devices, re-launching the app would detect that the user has been deleted. I also tried to use isLoggedIn but for authenticated devices, it seems always stays “true”.
RealmApp.shared.currentUser?.isLoggedIn
How to detect Realm app user has been deleted on other existing logged-in devices?
User presence is a challenge with Realm; it doesn’t have a baked in user presence system.
While you can monitor when a user is Online or Offline by setting a flag or var when they log in or log out (for example) - there’s no way to monitor in-between or unexpected changes of presence or deletion.
For example, a user logs in - the app can set a var (synched with the server) to ‘Online’ that other devices are observing so their UI can be updated. Whenever that flag changes, other devices or users of the app will know about it.
But what if the app crashes, the user d/c’s for whatever reason or the user force-quits the app. That var is now “Stuck” to the on position and other devices would never know they were offline.
For this use case, you can add an observer to a object in Realm that stores user status and sync's with the server. If the user logs out on one of the devices they are logged into for example, the other devices could be notified of that change. If the user is deleted, a "is deleted" flag could be set which notifies other devices or users of that change.
Expanding on that a bit - Deleting a user could trigger a server side function to then followup with perhaps removing all of their data, cleaning up references or notifying other devices of that event.

Send push notification to specific user?

I'm making an app where I want to be able to set a basic notification (title, message, fire date) and have been trying to figure out the best way to setup the notifications. I'm working with Swift 3 and Firebase 3.
I don't want to use local notifications because if the user is logged in on multiple devices I want it to push to all those devices.
Is there a way to do this with FCM where a user can set a notification to fire at a specific date and time and have it fire on all (iOS) devices logged in?
If FCM doesn't have this, is there another APK that does? I've looked at Batch briefly but I'm already using Firebase.
Thanks in advance!
If your main use case is to send a push notification to a single user for his multiple devices, I suggest you make use of Device Group Messaging on iOS. As per the docs, it is typically used for:
With device group messaging, app servers can send a single message to multiple instances of an app running on devices belonging to a group. Typically, "group" refers a set of different devices that belong to a single user.
When it comes to sending the notification on a specific date, I'm pretty sure you can set it up in the Firebase Console.
However, if you intend it to be sent from the server, you have to implement it yourself, since I think, there is no currently API available or a parameter you can set in the payload that can be modified for the message to be sent for a specific date.

Call status change web-service when my App is deleted

In my application , i works with web-services and when user log in into my app my app is sending a request with status 1 means loged in and when on log out button click sending a request with status 0.
Now problem is , when user removes app from devices , status in my server is remain 1(log in) , hence other user can see him available while his app is not in device. so is there any way by which i can send request when my app removes from device (i don't think it is possible) or is there any other way that i can do in my backend side ?
Thanks in advance.
It is not possible to call a web service when the user deleting the app from an ios device. There are three methods to came to know that whether your application is there in user's ios device. But there are few limitations also.
Activate Push notification: By doing this, device will get registered with Apple's push notification service. When user delete the app from device, the registration will be revoked from APNS server and through the APNS feedback service, you can get to know whether the application is existing. (Limitation: If the user did not agree with receiving push notifications, then the app will not be registered with APNS and you never came to know that whether application is existing or not)
Activate Location Based service: If your application enables location based service, then your application will get periodic location updates in a location delegate method. In this delegate, you can call a webservice and keep update the status of user even the application is in background. (Limitation: If user disables the location update, then your server will not get info about user status)
Periodically Call a Webservice From you app: This is possible only if your app is active. (Limitation: When you application pushed in to background, your application will be in suspended mode, so it will not possible to call webservice)
Sorry Unfortunately Apple not provide any method that user Uninstall app from user's device, There is no such method.
When user delete any application device does give the alert "Do you want to delete this application" with option "Delete" and "Cancel". You don't have to write any specific code for this.
I just assume that There is one method in which you can find out when user is about to delete your app. That is you need to implement push notification Apple server will inform you when you try to push to an uninstalled instance. Other than that there's no way to detect it but i am not sure its helpful or not.
You can't do this from within the app. You would want to do something like have a periodic task which runs on the backend, checking the last activity date of logged in users and setting them to 'not available' after some configured period of inactivity. This will probably require some changes to the backend to record last activity date and a change to the app so that while it's open it sends a periodic 'heartbeat' to the backend. You probably want to make the timeout quite big (say 15 minutes, big enough to not have a large impact on performance).

How can I send apple push notifications based on userIDs not only on device tokens?

I use push notifications in my iOS application but the problem is - several users with different IDs in the system can use the same device and I want to send push notification only to the user which is logged in, but now notifications arrive to the device even if other user is logged in. I know that APNS identifies pushes only by device tokens...
But is there some way to send push notifications based on user ID or other information not only device token?
You'll have to manage it yourself.
Whenever a user logs-in to your app, notify your server (send the user-id to the server).
Do the same whenever a user logs-off.
In your server, based on the currently logged-in user (you'll have to manage a database that contains for each device token the currently logged-in user), you can decide
which push notification to send to the device.
I don't think iOS push notification is right for your problem. here is why
consider you have an app with multiple users using the same device. you have a simple scenario where users can assign tasks to other users and they would like to get notifications when a task has been assigned to them
you do 'user to device token' mapping yourself on the server. consider user A and user B. both registered to receive notifications. so on the server both of them will have an entry in the mapping of what their device tokens are
Now, user B is logged out -- you will update on the server by removing the token for user B? or say use a flag to update the status that he is logged out?
user A now assigns a task to user B. on the server, you can see that user B has no mapping or mapping status is not active?
what happens to the notification?
you will end up queuing a notification for user b until he logs in? and push again? but again how do you know when to push again?
It is better you provide some UX in the app to get the notifications on a tap or periodically poll the server for any notifications

Handle APNS Remote Notifications while in Background

I have implemented all recommended methods in AppDelegate to get working Remote Notifications service.
I can accept them while running, while launching and while turned off.
But there is an issue, since I can't work with many received notifications while in background. I can work only with latest notification.
What is recommended manual to do that? How can I got all notifications received while in background? Is it only solvable via manual call to my service provider (sender of apns data)?
With all the projects I've worked on there hasn't been a way to locally store this information if the push notification is dismissed. In all those cases we used a small file on the server that the app would connect to and pull when it became active again. There was also some place in the app where the user could see all their notifications which, again, were stored on the server for quick retrieval.
With the way I understand push notifications to be setup, if the notification is dismissed the system discards it. It'll perform anything it's supposed to do (such as update the badge number and play the correct sound) but any additional information specific to that notification is lost.
Not sure if this helps, but if you just want to know how many notifications you have missed while you were in background. You can create a variable which contains notification number and store this in the app every time you handle notification. When you come out of background and receive a new notification you can subtract the new number with the stored number to find out the number of missed notifications. I don't think there is a way where iOS can give you complete data associated with all the notification device have received while the app was in background.
The best solution is to keep a list of sent notifications with all relevant data on your server, so the app can access that data when it launches. Sending multiple notifications with data that is not stored on the server can be risky, because the application only receives the notification when the user opens the app from that notification, so if they tap on one notification, the app will only every receive that one.
If you have them all in a list on your server, the app can simply go and pull that list down, and process it, making sure no data is lost.