15

I have implemented application:didReceiveRemoteNotification:fetchCompletionHandler: in my application delegate to respond to push notifications.

When a notification is received while the app is in the background, this method is called immediately and I fetch new data and execute the completion block when done. All as per the documentation. However, if I tap the notification alert this method gets called again, resulting in another network call and a UI update. I would have expected this method to be called once for each push notification, not once on receipt and again on action.

How have others implemented this method?

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [self loadSomeResource:^(NSData *data,NSError *error){
        if (error) {
            completionHandler(UIBackgroundFetchResultFailed);
        }
        else if (data){
            completionHandler(UIBackgroundFetchResultNewData);
        }
        else {
            completionHandler(UIBackgroundFetchResultNoData);
        }
    }];
}
Alex
  • 7,905
  • 4
  • 25
  • 31

2 Answers2

31

Here are the things to be noticed in application:didReceiveRemoteNotification:fetchCompletionHandler: method when you receive a push notification:
1. When the app is not launched (i.e, when the app is neither in background nor in foreground), the method is called once and applicationState will be UIApplicationStateInactive.
2. When the app is in foreground, the method is called once and applicationState will be UIApplicationStateActive.
3. When the app is in background, the method is called twice, once when you receive the push notification, and other time when you tap on that notification. When you receive the push notification, applicationState will be UIApplicationStateBackground and when you tap on that notification, applicationState will be UIApplicationStateInactive.

We can ignore it when the applicationState will be UIApplicationStateBackground and hence we can handle the push notification only once for all the three scenarios.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    if (application.applicationState == UIApplicationStateBackground) {
        completionHandler(UIBackgroundFetchResultNoData);
        return;
    }

    // Do whatever you need here and call completionHandler with appropriate UIBackgroundFetchResult
}
Ganesh Kamath
  • 1,161
  • 10
  • 19
  • 3
    This wouldn't solve the issue if you need separate logic for when the remote notification was received and when it is launched by a notification. How would you distinguish and know which is which, as now `UIApplicationStateInactive` could be invoked when the user is opening the notification or when the app is in inactive state when the notification is received? An example of a use case would be needing a timestamp for when the remote notification was received. – haitham Jan 30 '17 at 22:52
  • @HaithamMaya did you found any solution? – Radu Ursache Feb 07 '18 at 18:10
0

Check your application.applicationState to know if you are in the background or inactive and act accordingly.

Collin
  • 6,639
  • 4
  • 23
  • 29