Push notification Token generation may take more time than expected - ios

I have implemented push notifications in a project, and I am getting the push notification tokens correctly. I am sending this tokens with login api.
-(void)application:(UIApplication* )application didRegisterForRemoteNotificationsWithDeviceToken:(NSData* )deviceToken
{
NSString *devToken = [[deviceToken description] stringByTrimmingCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
devToken = [devToken stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"token: %#",devToken);
self.pushNotificationToken = devToken;
[[NSUserDefaults standardUserDefaults] setObject:devToken forKey:#"PushToken"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I am getting token perfectly. But some time I think it may take some more time to generate a token. Because of the login api does not contain token. I have checked database stored the token. Some time it is NULL. When I logout and login then the database contains the token and works perfectly. What is the perfect way to sending push token to server?

after experimenting this scenario push token generation may take anytime.There is not specific time duration. Mostly it will generate when app launches but we can not ensure.So better call api when we get token in delegate
-(void)application:(UIApplication* )application didRegisterForRemoteNotificationsWithDeviceToken:(NSData* )deviceToken
{
NSString *devToken = [[deviceToken description] stringByTrimmingCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
devToken = [devToken stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"token: %#",devToken);
//Call API to Update Device Token
}
Call the api to update token when token generated.

Related

Receive null device token sometimes

I'm currently working on project that allows user to receive push notifications whenever there is something new on the user account. I'm using Parse as my push notifications service. I'm having no problem until recently our server starting to receive empty token device on every push notification registration, this problem is not always happening. So when I tried the app on my device it just run as it should but when my app tested on our client device , our server receive an empty token device for that client user. How can this happen? How can I fix this? And how is the best practice to get and set the device token?
Here is my code in appdelegate:
- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
const unsigned *tokenBytes = [deviceToken bytes];
NSString *token = [NSString stringWithFormat:#"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
//function for saving device token to server
[[ASEngine defaultEngine] setCurrentDeviceToken:token];
if([[ASEngine defaultEngine] currentCredential] != nil) {
[[ASEngine defaultEngine] webStoreDeviceToken:token];
}
//save current instalation to parse
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
NSLog(#"Error e current installation: %#", error);
}];
//save device token locally
[[NSUserDefaults standardUserDefaults] setObject:deviceToken forKey:#"deviceToken"];
}
An empty token wont ever be generated,
iOS provides didFailToRegisterForRemoteNotificationsWithError method which is being probably called in your case, please make sure to check that for any errors in token creation.
Sometimes it happens when your device is not connected to internet.
Make sure your device is connected to internet.

Get device token for iOS push notifications at certain point in app

I've tried Googling, and keep hitting the same sorts of answers, ie.
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#"<>"]];
token = [token stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"content---%#", token);
}
However, I'm struggling to see how I might call/invoke this method in my App Delegate at a given event.
In my app, the first screen they see is login/signup. So on success of signup, I'd like to grab the device token and send it to my server to save against that new user. How exactly can I invoke this method from within a View Controller (or wherever) at a given time/event of my choosing, (and not just when the app first boots up)?
Hi try to use NSUserDefaults to store this data.
[[NSUserDefaults standardUserDefaults] setValue:deviceTokenString forKey:#"deviceToken"];
And to get this data use:
NSUserDefaults *data = [NSUserDefaults standardUserDefaults];
NSString *string = [data objectForKey:#"deviceToken"];

Worklight : get device token

Can worklight return the device token for Android/iPhone/BB and if so how?
More specifically, I'm not looking for the "device id" but the native device token.
Worklight can return the "device id", but this is different than the device token. For example Worklight: How to get current device ID for Push subscription states how to get the "device id" using the call
WL.Client.getUserInfo("wl_deviceNoProvisioningRealm", "userId");
Unfortunately this returns something different than the device token. When using the native iPhone call like so and comparing it to the WL deviceid it's obvious they are different.
- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSMutableDictionary *results = [NSMutableDictionary dictionary];
NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:#"<"withString:#""]
stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
[results setValue:token forKey:#"deviceToken"];
#if !TARGET_IPHONE_SIMULATOR
[results setValue:[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleDisplayName"] forKey:#"appName"];
[results setValue:[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"] forKey:#"appVersion"];
NSUInteger rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
// Set the defaults to disabled unless we find otherwise...
NSString *pushBadge = #"disabled";
NSString *pushAlert = #"disabled";
NSString *pushSound = #"disabled";
if(rntypes & UIRemoteNotificationTypeBadge){
pushBadge = #"enabled";
}
if(rntypes & UIRemoteNotificationTypeAlert) {
pushAlert = #"enabled";
}
if(rntypes & UIRemoteNotificationTypeSound) {
pushSound = #"enabled";
}
[results setValue:pushBadge forKey:#"pushBadge"];
[results setValue:pushAlert forKey:#"pushAlert"];
[results setValue:pushSound forKey:#"pushSound"];
// Get the users Device Model, Display Name, Token & Version Number
UIDevice *dev = [UIDevice currentDevice];
[results setValue:dev.name forKey:#"deviceName"];
[results setValue:dev.model forKey:#"deviceModel"];
[results setValue:dev.systemVersion forKey:#"deviceSystemVersion"];
[self successWithMessage:[NSString stringWithFormat:#"%#", token]];
#else
[self successWithMessage:[NSString stringWithFormat:#"%#", #"simulator generated"]];
#endif
}
Moreover, the native device token is needed for a third party notification platform which is outside of worklight and so using worklights messaging system isn't feasible.
You're correct APNs device token and Worklight deviceId is two different things. In case you require APNs device token for using some 3rd party notification platform you can override the didRegisterForRemoteNotificationsWithDeviceToken method in your application delegate thus receiving full control over the device token once it arrives from APNs

iOS APNS: sending the device token to the provider in string format

I need to send the APNS device token of my iOS app to my provider by calling a service that expects JSON data in my request. I'm reading Apple's Local and Push Notification Programming Guide and it only says that the application:didRegisterForRemoteNotificationsWithDeviceToken: delegate method passes the device token as NSData and you should pass it to your provider encoded in binary data. But I need it to be converted to string in order to be able to send a JSON request to my provider.
I've also been reading several posts related to this, since it looks it is a common scenario, but I've found some different ways to convert such device token to string to send it, and I'm not sure which of them should be the most appropriate. Which would the most reliable way to deal with this be? I suppose my provider will need to convert this string back to call APNS, and I also need to store this token in the app in order to safely compare it with the new value if a new token is generated and application:didRegisterForRemoteNotificationsWithDeviceToken: is called, to send the token only if it has changed.
Thanks
You are right that you have to convert the device token from NSData to NSString to
be able to send it with a JSON object. But what conversion method you choose is completely
up to you or the requirements of the provider. The most common methods are a
hex string (see for example Best way to serialize an NSData into a hexadeximal string) or a Base64 string (using
base64EncodedStringWithOptions). Both are 100% "reliable".
Also you should always send the device token to the provider and not only when it has changed. The provider has to keep a database of all device tokens with a timestamp of
when it was sent last recently, in order to compare the timestamp with a possible response
from the "feedback service".
In didFinishLaunchingWithOptions method
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
After doing above lines of code ,add the method below
#pragma mark Push Notifications
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token_string = [[[[deviceToken description] stringByReplacingOccurrencesOfString:#"<"withString:#""]
stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
NSString* strURL = [NSString stringWithFormat:#"http://www.sample.com?device_token=%#&type=IOS",token_string];
strURL=[strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#",strURL);
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSLog(#"content---%#", fileData);
}
After the above listed steps you can use this delegate function to retrieve and handle push notification once it comes.The below added method will fire either the app is running in background or not.The method given below is available from ios7.0
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
const unsigned *tokenBytes = [deviceToken bytes];
NSString *hexToken = [NSString stringWithFormat:#"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
Converting data to bytes means we can count it. Removing spaces and <> is really not a good idea
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)_deviceToken {
NSString *str = [NSString stringWithFormat:#"%#",_deviceToken];
//replace '<' and '>' along with spaces before you send it to the server.
}
this has worked reliably for me on almost all web platforms.

IOS - How to disable push notification at logout?

My app registers the account at login in my server to enable push notification for a chat. Yet I haven't implemented yet the unregistration of the account at logout, so in this moment if I do the login with 2 accounts in the same device it can take the notification of both the accounts. At the same time, my notification center has a POST service which unregisters the 'login_name+ device token' from receive notification center. Where should I call it? Do I have to use unregisterForRemoteNotifications? I just want to unregister the account+Device token from push notification, not to disable the entire app notification forever.
Can I save my device token on didRegisterForRemoteNotificationsWithDeviceToken function like
$ [[NSUserDefaults standardUserDefaults] setObject:hexToken forKey:DEVICE_KEY];
and then, at logout, call my POST function "removeDeviceToken" like
NSString *deviceToken = [userDefaults objectForKey:DEVICE_KEY];
if(deviceToken != NULL){
[self.engine removeDeviceToken:deviceToken];
}
You can easily enable and disable push notifications in your application by calling
To register, call: registerForRemoteNotificationTypes:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
To unregister, call: unregisterForRemoteNotificationTypes:
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
For check use
Enable or Disable iPhone Push Notifications try this code
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone)
// Yes it is..
I'm not sure if i got it correctly, but if you don't want to disable push notifications for the app, then you should't call the unregisterForRemoteNotifications. What you can do is, when the user taps the logout button, you can make a logout request to your server, which then removes the notificationID from that account, and after the logout request is completed, you just perform the logout locally (update UI etc).
More info about comment:
Yes, first of all, you should call registerForRemoteNotificationTypes method at every launch, because device token can change. After the delegate method
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken
is called, you can get the device token and save it to NSUserDefault. That way when the user logs in, you can get the up-to-date device token (if changed), and send it to your server to be added to that account.
So the code might look like this
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
NSString *newToken = [devToken description];
newToken = [newToken stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
newToken = [newToken stringByReplacingOccurrencesOfString:#" " withString:#""];
NSString *notificationID = [newToken description];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:notificationID forKey:#"notification_id"];
[prefs synchronize];
}
So, now when the user logs in, just get the notification ID and send it to your server
- (IBAction)userTappedLoginButton {
// Make your login request
// You can add the notification id as a parameter
// depending on your web service, or maybe make
// another request just to update notificationID
// for a member
NSString *notificationID = [[NSUserDefaults standardUserDefaults] objectForKey:#"notification_id"];
...
...
}
With Swift:
To Register,
UIApplication.shared.registerForRemoteNotifications()
To unregister,
UIApplication.shared.unregisterForRemoteNotifications()
In general it is a bad idea to unregisterForRemoteNotifications after logout and reregister after login. The reason is simple: if the user logins with another account and you don't specifically check for token overlapping in server, the user will start receiving double notifications.

Resources