IOS - How to disable push notification at logout? - ios

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.

Related

I want to do a badge increment on the main app icon while receiving a notification in inactive mode of the app

I am working on a chat app in react-native iOS. I want to do a badge increment on the main app icon when a notification is received, when the app is killed or force quit by the user. It works well when the app is in the background mode. But the didReceiveRemoteNotification method is not called when the app is inactive. Any idea on this? I added code inside the didReceiveRemoteNotification method of AppDelegate.
Added the following code set in AppDelegate file
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"APPDELEGATE: didReceiveRemoteNotification:fetchCompletionHandler %#", userInfo);
int badge = (int) application.applicationIconBadgeNumber;
if ( application.applicationState == UIApplicationStateInactive ) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge+1];
}
else if(application.applicationState == UIApplicationStateBackground) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge+1];
}
else if(application.applicationState == UIApplicationStateActive) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge+1];
}
completionHandler(UIBackgroundFetchResultNewData);
}
You need to create a UNNotificationServiceExtension to handle notifications when app is in background/killed.
It's a small application that will be executed on notification reception and has limited time to edit its content before presenting it to the user.
When you receive a notification in it's didReceive(_:withContentHandler:) delegate callback you can modify badge value of UNNotificationContent
In order to catch the incoming notification when the app is in the background or killed, use a UNNotificationServiceExtension in your project. The Info.plist for the UNNotificationServiceExtension (not the normal Info.plist for the main app; that one has normal things for the main app) might look something like
In the - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler of the UNNotificationServiceExtension, you can update the badge the following way:
self.bestAttemptContent = [request.content mutableCopy]; to get the request's content
self.bestAttemptContent.badge = <desired_integer_value> , where <desired_integer_value> would be the integer that you wish to put for the badge count.
self.contentHandler(self.bestAttemptContent); to complete the update of the content.
In many cases, the badge count may need to reflect a value (like number of unread chat messages) for a particular user. For that, you can use a shared user defaults. In fact NSUserDefaults supports the concept of app suite to allow such sharing. See Apple documentation for more details. In particular,
You can use this method when developing an app suite, to share preferences or other data among the apps, or when developing an app extension, to share preferences or other data between the extension and its containing app.
The argument and registration domains are shared between all instances of NSUserDefaults.
In a Constants.h file, have something to track individual counts for each user like
#define NOTIFICATIONS_UNREAD_SHARED [NSString stringWithFormat:#"notificationsUnread-%#",[mySharedDefaults objectForKey:USERNAME]]
and in your app, you would save the individual counts for each user, to the app suite's shared user defaults, with something like
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.yourCompany.yourAppname"];
if ([[NSUserDefaults standardUserDefaults] objectForKey:USERNAME]) {
mySharedDefaults setObject:[[NSUserDefaults standardUserDefaults] objectForKey:USERNAME] forKey:USERNAME];
[mySharedDefaults setObject:[NSNumber numberWithInteger:arrExistingRead.count] forKey:NOTIFICATIONS_READ_SHARED];
[mySharedDefaults setObject:[NSNumber numberWithInteger:([AppConstant sharedconstant].countObj.arrAllMessages.count - arrExistingRead.count)] forKey:NOTIFICATIONS_UNREAD_SHARED];
[mySharedDefaults synchronize];
}
Then in your UNNotificationServiceExtension, you would do something like
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.yourCompany.yourAppname"];
if ([mySharedDefaults objectForKey:NOTIFICATIONS_UNREAD_SHARED]) {
if ([mySharedDefaults objectForKey:USERNAME]) {
self.bestAttemptContent.badge = [NSNumber numberWithInt:[[mySharedDefaults objectForKey:NOTIFICATIONS_UNREAD_SHARED] intValue]+1];
} else { // username somehow not set; reset badge to 0
self.bestAttemptContent.badge = #0;
}
} else { // notifications unread count not found for this user; reset badge to 0
self.bestAttemptContent.badge = #0;
}
Troubleshooting
In case the extension doesn't appear to be receiving the push notifications, some things to verify:
Look at the build targets. Besides the main app, there should be one for the extension too.
In the settings for the main app, it should associate with the UNNotificationServiceExtension :
You need to set the badge field in the payload in the push notification.
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification
You will have to do the calculation server side.

Quickblox 'automatic push notifications for offline user' not working

I have following scenario.
User A sends message to User B in foreground -- this is working
Send push notification to User B, when app is in background, from 'Messages' console -- this is working
I want to send notification alert to User B when app is in background. I read that this is done automatically by quickblox, but is not happening for me.
I have followed instructions on this link
I am using 'Starter' account in development mode. Do we need account with ' server side history' for this functionality?
Edit 1:
Clarification: I want to send 'automatic push notifications for offline user' and not notification from app. I am also sending 'save_to_history' flag as mentioned on the link.
for Sending push notification use below code
-(void)applicationDidEnterBackground:(UIApplication *)application
{
[self sendMessageNotification:#"Hello Push notification" :1234 ];
}
-(void)sendMessageNotification:(NSInteger)recipientID message:(NSString*)message
{
isSentPushNotification = YES;
//[self sendPushNotificationToUser:message ids:#"1" audioFileName:#"default"];
NSMutableDictionary *payload = [NSMutableDictionary dictionary];
NSMutableDictionary *aps = [NSMutableDictionary dictionary];
[aps setObject:#"default" forKey:QBMPushMessageSoundKey];
[aps setObject:message forKey:QBMPushMessageAlertKey];
[aps setObject:#"1" forKey:QBMPushMessageAlertLocArgsKey];
[payload setObject:aps forKey:QBMPushMessageApsKey];
QBMPushMessage *pushMessage = [[QBMPushMessage alloc] initWithPayload:payload];
// Send push to users with ids 292,300,1395
[QBRequest sendPush:pushMessage toUsers:[NSString stringWithFormat:#"%lu",(long)recipientID]successBlock:^(QBResponse *response, QBMEvent *event) {
NSLog(#"Successfully dilivered push notification");
} errorBlock:^(QBError *error) {
NSLog(#"Fail to diliver push notification %#",error);
}];
}
But you should first Subscribe User to receive Push Notifications
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
// Register subscription with device token
[QBRequest registerSubscriptionForDeviceToken:deviceToken successBlock:^(QBResponse *response, NSArray *subscriptions) {
// Registration succeded
} errorBlock:^(QBError *error) {
// Handle error
}];
}
for more detail please have a look of this
Found the problem.
We have to logout from the the chat when the app enters background.
I think, this might be required to let server know that we are actually offline and it should send us push notification instead. (just a guess!!)
I think logout thing was mentioned in documentation as well but I didn't know that it was so important.

get device token without enter to the function didRegisterForRemoteNotificationsWithDeviceToken

I have in the settings page a button to let the user enable or disable the push notification.
If the user doesn't allow to receive push notification the first time he launch the application, how can I get the Device Token if the user turn on the notification setting later in setting page?
Thanks.
No, you can't, you can't get the device token unless the user allows you to, and once user allows it, you have to retrieve device token from the didRegisterForRemoteNotificationsWithDeviceToken call back.
If the user denied your push notification request for the first time, until the user enable push notification service for you app in Setting.app->Privacy, you can't get the token.
So you should check
[[UIApplication sharedApplication] enabledRemoteNotificationTypes]
every time user changes the setting of notifications in you App,
if the result is that notification is not enabled, you should guide the user to change the notification setting in Setting.app->Privacy;
if the result is that notification is enabled, you use this code to retrieve the token:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert]
this will trigger the -didRegisterForRemoteNotificationsWithDeviceToken callback.
No its not possible , when user authenticate the allow permission and run your project , it automatically call the method didRegisterForRemoteNotificationsWithDeviceToken else it call the didFailToRegisterForRemoteNotificationsWithError
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:
(NSData *)deviceToken {
NSString* deviceTokene = [[[[deviceToken description]
stringByReplacingOccurrencesOfString: #"<" withString: #""]
stringByReplacingOccurrencesOfString: #">" withString: #""]
stringByReplacingOccurrencesOfString: #" " withString: #""] ;
NSLog(#"%#",deviceTokene);
}
this is the coding to enable the APNS in Viewcontroller
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge
|UIUserNotificationTypeSound
|UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
if you want to disable the APNS in inside the VC
[[UIApplication sharedApplication] unregisterForRemoteNotifications];

track user choice for Push Notification [allow/don't]

When an application need to register for push notification (UIApplication registerForRemoteNotificationTypes) a popup show Allow/Don't choice.
Is there a way to track when the user take this choice ?
Because the solution:
NSUInteger rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
is fine, but until the user touch something it's NO by default. I should only check this config after the user make a choice.
The consequence is that in my EasyAPNS server most of the application are in 'disabled' mode until the user relaunch them (because the second time the correct config will be pushed to my sever). So with the first launch the real choice of the user is probably not taken into account (if you accept really rapidly, before my app register to EasyAPNS then your choice is reflected back on the server at first launch)
Any idea ?
There seems to be no way to determine whether the allow pop-up has been shown. I rely on user defaults to keep track of this:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
BOOL didRegisterForPush = [[NSUserDefaults standardUserDefaults] boolForKey:#"didRegisterForPush"];
if (!didRegisterForPush) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"didRegisterForPush"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
// .. send deviceToken to server
}
Now you can determine the authorization state using:
- (PushAuthorizationStatus)pushAuthorizationStatus
{
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types) {
return kPushAuthorizationStatusAuthorized;
}
BOOL didRegisterForPush = [[NSUserDefaults standardUserDefaults] boolForKey:#"didRegisterForPush"];
if (didRegisterForPush) {
return kPushAuthorizationStatusDenied;
}
return kPushAuthorizationStatusNotDetermined;
}
Using this you can send the NotDetermined state to the server instead of Denied.
Under iOS 8 and later the procedure is a little different. In iOS 8 the enabledRemoteNotificationTypes method was replaced by isRegisteredForRemoteNotifications.
However isRegisteredForRemoteNotifications always returns YES if the app attempted to register for notifications, regardless of whether the user actually allowed them or not.
To determine whether the user actually allowed notifications, use the function provided by #Lefteris here:
- (BOOL)pushNotificationsEnabled {
if ([[UIApplication sharedApplication] respondsToSelector:#selector(currentUserNotificationSettings)]) {
UIUserNotificationType types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];
return (types & UIUserNotificationTypeAlert);
}
else {
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
return (types & UIRemoteNotificationTypeAlert);
}
}

"Myapp would like to send you push notifications" message not appearing in my app, but it still allows push notifications to appear

As the title says, when I first start up my app the dialog asking the user whether or not they want to receive push notifications doesn't appear. However if you go into settings the app appears in the push noticifications section, and the app DOES receive the push notification.
I'm using this to register for push, have I missed something out:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
I'm led to believe that if this is in didFinishLaunchingWithOptions that the prompt for the user would automatically appear?
Edit: I forgot to add that I do also have a didRegisterForRemoteNotificationsWithDeviceToken function in there too, to retain the token. As I say the notifications work in the sense that the user receives them, but the "do you want to receive them" popup never appears - which I would imagine are grounds for rejection by Apple.
Something like this is needed to retain the token:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [[[deviceToken description]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]]
stringByReplacingOccurrencesOfString:#" "
withString:#""];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:[NSString stringWithFormat:#"%#", token] forKey:#"DeviceToken"];
NSLog(#"APNs Device Token: %#", token);
}
See this thread also: didRegisterForRemoteNotificationsWithDeviceToken - Push Notifications

Resources