Get device token for push notifications after app was deleted - ios

When you install an app for the first time and want to register for Push notifications, the app asks you whether you want to receive alerts or not. This is being permanently saved in the settings, even after deletion of the app.
Basically, to save the token we are doing this:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [[[deviceToken description]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]]
stringByReplacingOccurrencesOfString:#" " withString:#""];
[[NSUserDefaults standardUserDefaults] setValue:token forKey:kDeviceTokenKey];
}
But the problem is, NSUserDefaults are wiped when the app is removed from the device, but the push settings are not. So it won't ask again, thus don't call the delegate method again, thus I don't have the token anymore, but push is still activated.
Is there any chance to get the token back in the described scenario?

From Push Notification Programming Guide
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.
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.
To answer your question: Call registerForRemoteNotificationTypes: on every launch, and use the latest token.

call registerForRemoteNotificationTypes on every launch of your application so your didRegisterForRemoteNotificationsWithDeviceToken method get call and you will get your device token every time from APNS. And device token for your application is same on every launch.

Related

How to determine when to update deviceToken for push notifications / how to get it?

I've had various struggles with push notifications over the course of my app that seem to be fixed by uninstalling. I believe I've narrowed it down to expired deviceTokens.
Reading Apple's Push notification documentation, I found this:
Registration Succeeded But No Notifications Received
. . .
Your app may have sent an incorrect device token to your provider.
Your app should always ask for the device token by registering with
the push service each time it is launched. Don't store a device token
from your app and try to reuse it, because the token can change. Your
provider should then pass that same token on to the push service.
They suggest registering each time the app is launched. They also suggest best practice for push notifications is not to do that, since users don't like getting bombarded with access requests before even getting to see your app. So, just throwing the registration call into the app delegate isn't the best option. However, I am not seeing any more info on when a deviceToken expires or how to see if it has expired.
The closest thing I can find is this documentation on UIApplication's instance method isRegisteredForRemoteNotifications:
Return Value YES if the app is registered for remote notifications and
received its device token or NO if registration has not occurred, has
failed, or has been denied by the user.
My understanding is that this is the method to call to check if a user has enabled push notification services. I understand that permissions for specific notification types could all be turned off and this could still be true if the user allows push notifications. But the wording looks like it requires the app to be registered with the current deviceToken. Does this mean that I could call
[[UIApplication currentApplication] isRegisteredForRemoteNotifications]
inside the appDelegate, and if it's true, register remote notifications to update my deviceToken on my server and make sure my push notifications don't expire? Or, is this function going to run into the same thing that I currently am, where eventually the deviceToken is going to expire and this method will begin to return false instead of true, even though the user had allowed push notification?
tl;dr - Apple says deviceTokens eventually expire for push notifications. They suggest registering every time the app launches. I don't want to bombard new users with that alert. How do I ensure only users who have already accepted push notifications get re-registered?
The alert will only be shown once.
If the user previously Allowed notifications, your code will get the new token without needing any interaction from (or UI notice to) the user.
OK, the best practice for this are as follows, which we follow without failure
Always register for the Push on app launch, or in suitable AppDelegate lifecycle methods, using the following code
[[UIApplication sharedApplication] registerUserNotificationSettings: [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
The delegate for Push if it is successfully registered will get called with deviceToken
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
The delegate above will get called if there is change in deviceToken always. So whenever you get a deviceToken update it in the server.
In the server make sure you hit correct mode if you are running in Sandbox, or Production mode, discard values from Simulators they normally fails and block the service for sometime.
You can always check with your pem file and device token that Push is working or not with this online service.
Hope it helps.
Cheers.

iOS-GCM integration: does registration need to happen every time

Do you need to register your APNS device token with GCM every time via:
tokenWithAuthorizedEntity:scope:options:handler
every time the app is launched, EVEN IF the device token is identical.
According to a sample app for GCM, every time the app is launched, [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:_gcmSenderID [1] is called. This is because the registration is invoked from didRegisterForRemoteNotificationsWithDeviceToken which does need to be called every time the app is launched - "Device tokens can change, so your app needs to reregister every time it is launched and pass the received token back to your server." [2]
Can I store the registrationToken and deviceToken and only reregister when the deviceToken changes? The presence of GGLInstanceIDDelegate#onTokenRefresh seems to suggest that there is a mechanism to be notified when the registrationToken changes for your deviceToken, but I would like this to be confirmed.
[1]https://github.com/googlesamples/google-services/blob/master/ios/gcm/GcmExample/AppDelegate.m#L151
[2]https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html
In Google's official GCM Client Demo App, registering every time the app starts ensures that your servers gets the Registration ID even if it lost it somehow, but that shouldn't be an issue if your Registration IDs are persisted properly in the server.
Note that google may periodically refresh the registration ID, so you should design your app that be called multiple times. Your app needs to be able to respond accordingly.
To summarize, you should always treat the Token as if it may change any time you restart your application.

Should we register for iOS push notification every time during application launch?

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

Does device token ever change in Apple Push Notifications

I am developing an iOS app in which i have implemented Push Notification.
Everything is working fine.
But just wish to ask if device Token for my Apple device will ever change??
Also do we need internet connectivity for generating device token.
Thanks
device Token for my Apple device will ever change
-- YES. If you restores backup data to a new device or reinstall the operating system, the device token changes. So my suggestion is to update the server with token
do we need internet connectivity for generating device token
-- as far as I know, YES. When you register user, you call method for registration for push notification. This on successful registration call the delegate method -
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
indicating you are registered successfully for a push notification or on failure it calls -
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
indicating failed to register for notification.
You can check it by turning off network and running your application.
Based on the Apple Documentation, the answer is YES:
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.
From the apple docs -
The device token is your key to sending push notifications to your app on a specific device. Device tokens can change, so your app needs to reregister every time it is launched and pass the received token back to your server. If you fail to update the device token, remote notifications might not make their way to the user’s device.
Device tokens always change when the user restores backup data to a new device or computer or reinstalls the operating system. When migrating data to a new device or computer, the user must launch your app once before remote notifications can be delivered to that device.
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.
For more APNS Doc
I was recently troubleshooting an issue with push notifications for a user. I was a bit confused by the guidance here, indicating that the token would only change in rare circumstances, such as "moving to a new device" or "re-installing the OS".
While the above events are likely valid events where the token is updated, I also see the token is updated simply when the user updates the OS on their device.
For example:
When my device runs iOS 15.4.1, and I install an application and request a push notification token, I'm provided with token "A".
After I update my device to iOS 15.7, with the same application still installed, and request a push notification token, I'm provided with token "B".
Therefore while rare events like restoring backup data to a new device or re-installing the OS are valid for this case, more frequent events such as a user simply updating the OS of their device are also valid for causing the push notification token to change.
Thus, this will likely change quite frequently and should always be requested from the device and updated on your server.

Disable Push Notification after New Installation of app without login

I have situation like this I am logging into the app then i am sending the device token to the server and i am getting the push notifications. If the consumer logs out from the app then i am sending a request to the server then i am not getting the push notification. If the user uninstall the app after logging in then i can't send a request to the server to stop the push notification then I install the app again but i didn't login then automatically I'm getting the push notification.
So my problem is how to stop the push notification when the user didn't login to the app
A bit late, but it might help someone.
I faced a similar situation in a project of mine:
The problem
First run gets the device token
user logs in and the app registers the device token with the server
user uninstalls the app without logging out hence the server still thinks it's active
user reinstalls app, and still receives push notifications even though they're not logged in yet
In my app I register and request for the device token in the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
..
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
..
}
And once the reply is received from Apple:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)token{
//Get trimmed device token
NSString *deviceToken = [[token description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
deviceToken = [deviceToken stringByReplacingOccurrencesOfString:#" " withString:#""];
//Store the device token in the user defaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:deviceToken forKey:#"dToken"];
[userDefaults synchronize];
}
This is more or less the typical way I've seen it done.
Now when the user logs in, the device token is sent to the server and registered from the main view controller of the user content area. The device token is retrieved by accessing the user defaults from within that view controller. The problem however is if the user never logs in to the user content area, the notifications will still persist because the device was never unregistered with the server as a result of the previous uninstall while still logged in.
The Solution
There are a few approaches to solving this problem as mentioned in other answers. However I didn't want to modify my server and the main structure of registering devices there, which goes something like:
When the user first logs in: authenticate the user and register the passed device token at the same time.
When the user logs out: unregister the device token to that user.
Whenever a device token exists in the DB: deactivate it for all users except for the user currently logging in.
Seeing that the user content area must have the device token to log in the user, I start by requesting the device token in didFinishLaunchingWithOptions as I did before.
Now when a reply is received in didRegisterForRemoteNotificationsWithDeviceToken I do the following:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)token{
//Get trimmed device token
NSString *deviceToken = [[token description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
deviceToken = [deviceToken stringByReplacingOccurrencesOfString:#" " withString:#""];
//Store the device token in the user defaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:deviceToken forKey:#"dToken"];
[userDefaults synchronize];
//If not logged in yet, unregister for notifications
if(![[NSUserDefaults standardUserDefaults] objectForKey:#"loggedIn"])
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
}
I check if the user content view controller has not been reached yet, i.e. the user never logged in, and disable the notifications.
In the user content view controller I do the following:
- (void)viewDidLoad{
..
//Set logged-in so the notifications continue to be received
if(![[NSUserDefaults standardUserDefaults] objectForKey:#"loggedIn"]){
[[NSUserDefaults standardUserDefaults] setValue:#"done" forKey:#"loggedIn"];
[[NSUserDefaults standardUserDefaults] synchronize];
//Register for notifications (again)
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
//Send user authentication and device token (retrieved from the user defaults) to server
..
}
Now whenever the user first logs in the device token is sent to the server and registered without any delays because it has already been retrieved from Apple. The notifications are also disabled until the user logs in and therefore the main problem is solved.
This approach insures that the user content area view controller is never loaded without the device token saved in the user defaults and therefore allows me to continue using the same method of authenticating the user and passing the device token at once.
You can identify when the app is launched for the first time (either after the first time it's installed or after being uninstalled and re-installed) by storing some data locally on your device (for example, you can store the device token).
When the app is launched for the first time, send the device token to your server in a request that would clear any DB entry that refers to that device token (the same request you send to your server when a user logs out). This way your server wouldn't send push notification to this device token until a user logs in.
The next time a user logs into the app, send the device token & the user id to your server in a request to start sending push notifications for that user using that device token.
I like this situation...Check my logic.
Fist important thing you have is that when the app uninstalled,its database also gets vanished.
this is the trick.
==>You have to maintain a reference number which start from 1.
(you may put it hard coded and only have to update)
use this reference number each time with your
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//get value from database,increment by 1
//sync with server
}
each time app gets started you have to increment the reference number also.
need to keep track of this reference number on server side also.
Second scenario(i.e. problem you facing) is when app gets reinstalled:
all database gets vanished automatically.==>this is the trick
when you use reference number next time from database it will be 1.
Now compare it with server-side.
After second scenario that is after app gets reinstalled your reference number will be less than current maintained one i.e(1< current maintained reference number #server)
this is the condition to know server that app is reinstalled and need to wait till authentication.
so make server to disallow notification for current device till login by user.and after successful login update all database and allow server to send notification.

Resources