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.
Related
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.
We are using remote notifications in our iOS application and we are registering to APNS server inside application: didFinishLaunching: delegate method. That means it will be registered with APNS server every time the application launched freshly. Below is the code snippet.
[[UIApplication sharedApplication] registerForRemoteNotifications]
We have noticed that the device token (which is delivered to us by APNS server) is same every time. So, we thought that we can save the token in NSUserDefaults and use it later. In application: didFinishLaunching: method, we can give a check if the device token is present in NSUserDefaults or not. If it's available, we can use the same instead of registering to APNS. Otherwise, we can opt to register with APNS.
But, from the Apple documentation, it's observed that "they encourage us to register for remote notifications each time the application is launched freshly". Below is the screenshot from docs.
When does the device token value change actually? Can I afford to store the device token in NSUserDefaults and use it later instead of registering every time? Please help!! Thanks in advance!!
To answer your question with some apple documentation:
The form of this phase of token trust ensures that only APNs generates the token which it will later honor, and it can assure
itself that a token handed to it by a device is the same token that it
previously provisioned for that particular device—and only for that
device.
If the user restores backup data to a new device or reinstalls the
operating system, the device token changes.
This means you shouldn't really store the token in your NSUserDefaults.
However if you want to save it anyway I recommend to save it in the Keychain.
See this example how to do so:
Store Device Token in Keychain
Another quote from apple documentation:
"By requesting the device token and passing it to the provider every time your application launches, you help to ensure that the provider has the current token for the device. If a user restores a backup to a device other than the one that the backup was created for (for example, the user migrates data to a new device), he or she must launch the application at least once for it to receive notifications again. If the user restores backup data to a new device or reinstalls the operating system, the device token changes. Moreover, never cache a device token and give that to your provider; always get the token from the system whenever you need it. If your application has previously registered, calling registerForRemoteNotificationTypes: results in iOS passing the device token to the delegate immediately without incurring additional overhead."
EDIT:
Looks like the above links to Apple's documentation are broken by now. Here is a updated link (thanks to #Enrico Cupellini): https://developer.apple.com/library/content/technotes/tn2265/_index.html
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. )
We added receiving push notifications to an iPhone app. Everything was working in the test/sandbox environment, we were getting token id's from the app and could send push notifications from our server.
But now the app is approved and came out of the Appstore we were getting empty push tokens/notifications id's send to our server. We already have over 600 of them... Note that end users do get the popup to approve of receiving notifications in the app, the app is just sending empty tokens to our server after approval. So probably empty tokens are handed out by the APNS server.
The following issue showed us that this is probably due to missing 'push notification' entitlement in the provisioning profile we used to make the build for the app store:
How do I check if an iOS distribution provisioning profile has push notifications enabled?
The missing entitlement was due to a bug in Apple's provisiong protal website, but after 'Modify any existing profile before you download the new one' as mentioned in the following article
http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ProvisioningDevelopment/ProvisioningDevelopment.html
We now have the correct entitlement in our .mobileprovision file:
<key>Entitlements</key>
<dict>
..
<key>aps-environment</key>
<string>production</string>
..
So we are rebuilding our app and adding it to the store. And hoping to get push notifications then.
I hope the above might help some others. But now to get to my actual question: Will we start receiving new push tokens also for the 600+ users that already downloaded the current version when they install the next update out of the store? Or do we need to add some initial code to our app? The registerForRemoteNotifications method is right now only called on application startup. Will it also be triggered when the push token id is changed from empty ('') to an actual token? Of course we do not want to wait another (small) week for the new AppStore approval and only then find out that push notification still aren't working for some users. I'm hoping some expert out there can tell us.
Note: We are using an iPhone app developed in MonoTouch, and using the (old) APNS-Sharp library to send the notifications from our server, but I don't think those details are relevant for this issue.
When those 600+ users install the next update and run the application again, your application will call registerForRemoteNotifications (since you said you call it on startup), and will get the non empty device token (when application:didRegisterForRemoteNotificationsWithDeviceToken: is called).
Apple state in their docs that you should always call this method at startup instead of using a cached copy of the device token, because the device token is not guaranteed to remain the same. So you shouldn't have any problem.
Here's the relevant quote from the APNS docs :
An application should register every time it launches and give its
provider the current token. It calls
the registerForRemoteNotificationTypes: method to kick off the
registration process. The parameter of this method takes a
UIRemoteNotificationType (or, for OS X, a NSRemoteNotificationType)
bit mask that specifies the initial types of notifications that the
application wishes to receive—for example, icon-badging and sounds,
but not alert messages. In iOS, users can thereafter modify the
enabled notification types in the Notifications preference of the
Settings application. In both iOS and OS X, you can retrieve the
currently enabled notification types by calling the
enabledRemoteNotificationTypes method. The operating system does not
badge icons, display alert messages, or play alert sounds if any of
these notifications types are not enabled, even if they are specified
in the notification payload.
This is also relevant :
By requesting the device token and passing it to the provider every
time your application launches, you help to ensure that the provider
has the current token for the device. If a user restores a backup to a
device or computer other than the one that the backup was created for
(for example, the user migrates data to a new device or computer), he
or she must launch the application at least once for it to receive
notifications again. If the user restores backup data to a new device
or computer, or reinstalls the operating system, the device token
changes. Moreover, never cache a device token and give that to your
provider; always get the token from the system whenever you need it.
If your application has previously registered, calling
registerForRemoteNotificationTypes: results in the operating system
passing the device token to the delegate immediately without incurring
additional overhead.
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.