Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 873
Beu Avatar asked May 04 '20 04:05

Beu


2 Answers

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

like image 170
LaughtingMan Avatar answered Oct 20 '22 00:10

LaughtingMan


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 enter image description here

In the - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler of the UNNotificationServiceExtension, you can update the badge the following way:

  1. self.bestAttemptContent = [request.content mutableCopy]; to get the request's content
  2. self.bestAttemptContent.badge = <desired_integer_value> , where <desired_integer_value> would be the integer that you wish to put for the badge count.
  3. 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. enter image description here

In the settings for the main app, it should associate with the UNNotificationServiceExtension : enter image description here

like image 22
auspicious99 Avatar answered Oct 20 '22 00:10

auspicious99