I'm developing an iOS app that enables the user to observe technical devices and be notified if there are problems.
What I know so far:
My app requests a token from the APNs.
My app sends this token to my server.
My server notifies the APNs in case of an event.
The APNs pushes a message onto the device.
What I want to know:
I read the token may change, therefor I need to request it on every app launch. Is this true?
If I get a new token from time to time I have to register at my server from time to time to make sure it uses the current token. Do I have to store and manually send the old token with the new one if the token changes to allow my server to delete the old one?
How can I detect that a user removed the app to remove his device on the server?
Highest priority in my case is for the server to know which devices are registered with the service. Old devices (old tokens that is) need to be removed immediately.
Thanks for your help.
You should register for the remote notification on every app launch and send the token to your server.
To check if the user removed the app or disabled notifications you have to check the feedback service. Look for it on this page:
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/BinaryProviderAPI.html#//apple_ref/doc/uid/TP40008194-CH13-SW1
Note: APNs monitors providers for their diligence in checking the feedback service and refraining from sending push notifications to nonexistent applications on devices.
Related
I am adding Push Notifications to my app and I know I need to store the device tokens in my database so that I can send push notifications to specific devices (or all devices).
My question is what is the best practice for maintenance of these device tokens? I can store all device tokens as they are received, but how can I detect and remove old device tokens that are no longer valid? I assume a device token can become invalid if user deletes the app, or if user turns off notifications for the app.
Update - Having a user authentication and linking it to the device token (and updating based on login/logout) makes sense. But what about if the user deletes the app? there is no logout, how do you remove the device token then?
The Apple feedback service is no longer used. Instead we have to look for a response status of 401 from the apple push notification service to determine that a token is invalid.
To test this in a development environment. Use the trick below (it says it's for feedback service, but should work with the new status code from APNS as well)
How to test Apple Push Notifications Feedback Service?
Use the APNS feedback service, to find the device tokens that belonged to an app that was uninstalled.
See this apple documentation
If you are using something like Amazon SNS for push notifications, you can use their API to get list of disabled arns and remove the corresponding device tokens from your database.
Make an webservice which stores user's device token in database for particular user. Call this webservice only if user is logged in or you have identify user as per your requirement. You need to call this webservice when device successfully register for notification and if user is not identify (i.e. not logged-in) then call this service after login api.
Also pass device token when in login and register API if you have according to your flow and replace device token for particular user.
And when user logout just unregister for notification
As you said in your last statement I assume a device token can become invalid if user deletes the app, or if user turns off notifications for the app.
General scenario is when user again login to the app or register to the app you need to again take the device token from the user and need to store it in your database
Suppose I had one app and again I install only that at that time whenever I login again to the app at that time the api must having parameter for deviceID so whenever api call happen for login at that time new device token take place in your database by just replacing the old one. Same thing will happen for new register with that app.
Hope above description help you. :)
Your app server won't know if a particular app has been forcefully deleted & your server would still have let's say token T1 mapped to deleted app/device let's say A1. Now, it may be possible that another valid user (A2) comes up with same device token T1. You just need to make sure that at any point of time one device token (i.e. T1) is mapped to only one device (the device which has provided the T1 latest). All other older device token mappings i.e. A1-T1 shall be deleted at this point else A2 might receive A1's notifications.
I want to make sure my server always has the up to date APNS device token, which can change under specific circumstances.
Should I save it to the Keychain, and on launch check if it's different, and then update the server if so?
Is that the best way to be doing this?
Apple actually say NOT to store the device token locally. You call registerForRemoteNotifications() when you need the device token. From Apple:
Never cache a device token; always get the token from the system whenever you need it. If your app previously registered for remote notifications, calling the registerForRemoteNotifications method again does not incur any additional overhead, and iOS returns the existing device token to your app delegate immediately. In addition, iOS calls your delegate method any time the device token changes, not just in response to your app registering or re-registering.
So what you need to do is register for remote notifications on launch, and send that token to your server. From Apple:
Device tokens can change, so your app needs to reregister every time it is launched and pass the received token back to your server.
You can find more documentation here: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html#//apple_ref/doc/uid/TP40008194-CH103-SW25
Sure thing, you need to register for push notifications every time the app is launched. Like the documentation from Apple says, you never know when and why the token can/will change.
Second, indeed you can have some code to store locally the token in case of a server error or loss of internet when you try to send it to your server. And this logic can retry with a delay and max try count. But this is pretty overkill and not KISS-like.
What you can do is send it as soon as you get it from didRegisterForPushNotification and store it locally and every time the user of your app does an "update settings" call send it at the same time also.
I'm trying to detect uninstalls of our iOS app.
I read this document which gives some useful information. However, how can I understand from the error codes returned whether the user uninstalled versus disabled push notifications/has no connectivity?
I think you'll want to use the Feedback Service. When a user deletes an app, the service provider should ideally stop sending notifications to that device. But Apple does not notify the service that "this device is not using your app, dont send notifications". Technically, a device which has uninstalled your app will not make it onto this list until the next time a push notification goes to the device. So you need to poll for this info using the Feedback Service.
Periodically, you will need to hit Apple Notification servers asking it to give you IDs that have deleted your app. Once you get them you mark them in your DB as deleted thereby not sending any more notifications. This Feedback Service will tell devices that have been unregistered (app uninstalled). The part I'm not sure about is whether a user who has turned off push notifications in settings will register the same. I believe they will not show up in the feed from the Feedback Service. I am certain, however, that users who are offline and the push notification is not delivered will not be included in the list.
It would be a simple test in your dev region to try the app, disable push notifications for the app, and then see if the device shows up in the feed.
Take a look at Apple's documentation
From Apple Documentation -
Apple Push Notification Service includes a feedback service that APNs
continually updates with a per-application list of devices for which
there were failed-delivery attempts. The devices are identified by
device tokens encoded in binary format. Providers should periodically
query the feedback service to get the list of device tokens for their
applications, each of which is identified by its topic. Then, after
verifying that the application hasn’t recently been re-registered on
the identified devices, a provider should stop sending notifications
to these devices.
Access to the feedback service takes place through a binary interface
similar to that used for sending push notifications. You access the
production feedback service via feedback.push.apple.com, port 2196;
you access the sandbox feedback service via
feedback.sandbox.push.apple.com, port 2196. As with the binary
interface for push notifications, you must use TLS (or SSL) to
establish a secured communications channel. The SSL certificate
required for these connections is the same one that is provisioned for
sending notifications. To establish a trusted provider identity, you
should present this certificate to APNs at connection time using
peer-to-peer authentication.
Make sure you also read up on - Issues with Feedback Service
Most documentation advises to register for remote notifications on launch, and on receipt of the token, push this to a server with any other app-specific settings (e.g. user, in-app Push settings). However, I am not sure how to handle the following corner case.
If the user launches the app without connectivity, no token will be received. Moments later, connectivity is restored. The user attempts to change some setting in the app, which should prompt a post to my server including the setting and the token. However, the token is still nil.
Would it not be better, instead, to register for notifications every time before attempting to post the setting? It seems unnecessary to request this token on launch since it might not be needed, and even worse, might be nil when it is needed.
I think it's still best to register for push notifications when the app is launched. When you get the device token, you don't have to immediately send it to your server. You can store it locally on the device. When your logic requires to send the device token (as well as other settings) to your server, get the locally saved token. If the saved token is null, try registering again, and send the token to your server once you get it.
Note that when the app is launched you should register for push notifications even if you a have a previous locally stored device token (due to the remote chance that Apple would decide to change the device token).
Apple recommends you should call register every time the app comes to the foreground ( either when you open it or when it comes back from background).
This call does not serve only as a way to get the push notification token but also to let Apple know that this application is still interested in receiving push notification. If you call this method only once, or rarely and you don't send push notifications that often, you could run into a scenario where the token you have been using, that is stored on the server is no longer a valid token (after enough time has passed without a token being acknowledged by a device apple will no longer consider the token valid. )
I implemented push notification in my app.
It is working fine.
Now the problem is even after i deleted my app from device it is getting the push notifications.
So is there any way to unregister the app from push notification when it is deleted from the device.
Hoping for your help.
Thanks in advance.
In Apple push notification there is something called - Feedback Service. So when a user deletes an app, the service provider should ideally stop sending notifications to that device. But Apple does not notify the service that "this device is not using your app, dont send notifications". So instead you need to poll for this info.
Every day you might need to hit Apple Notification servers asking it to give you device Ids who have deleted your app. Once you get them you mark them in your DB as deleted thereby not sending any more notifications. Hope this is what you wanted.
From Apple Documentation -
... Apple Push Notification Service includes a feedback
service that APNs continually updates with a per-application list of
devices for which there were failed-delivery attempts. The devices are
identified by device tokens encoded in binary format. Providers should
periodically query the feedback service to get the list of device
tokens for their applications, each of which is identified by its
topic. Then, after verifying that the application hasn’t recently been
re-registered on the identified devices, a provider should stop
sending notifications to these devices.
Access to the feedback service takes place through a binary interface
similar to that used for sending push notifications. You access the
production feedback service via feedback.push.apple.com, port 2196;
you access the sandbox feedback service via
feedback.sandbox.push.apple.com, port 2196. As with the binary
interface for push notifications, you must use TLS (or SSL) to
establish a secured communications channel. The SSL certificate
required for these connections is the same one that is provisioned for
sending notifications. To establish a trusted provider identity, you
should present this certificate to APNs at connection time using
peer-to-peer authentication.
Be sure to checkout - Issues with Feedback Service
Having not seen this answer so far, there is a small note in the Apple "Troubleshooting Push Notifications" document.
In short, if you delete the last push enabled app, the persistent connection from the device to Apples push server is broken before the server is told that the app has been deleted.
Solution: keep at least one push enabled app on your device.
There is the explanation from the document:
Issues with Using the Feedback Service
If you remove your app from your device or computer and then send a push notification to it, you would expect to have the device token rejected, and the invalidated device token should appear on the feedback service. However, if this was the last push-enabled app on the device or computer, it will not show up in the feedback service. This is because deleting the last app tears down the persistent connection to the push service before the notice of the deletion can be sent.
You can work around this by leaving at least one push-enabled app on the device or computer in order to keep the persistent connection up. To keep the persistent connection to the production environment up, just install any free push-enabled app from the App Store and you should then be able to delete your app and see it appear in the feedback service.
Recall that each push environment has its own persistent connection. So to keep the persistent connection to the sandbox environment up, install another development push-enabled app."