26
votes

As per the Apple guide:

"As a result of the presented notification, the user taps the action button of the alert or taps (or clicks) the application icon. If the action button is tapped (on a device running iOS), the system launches the application and the application calls its delegate’s application:didFinishLaunchingWithOptions: method (if implemented); it passes in the notification payload (for remote notifications) or the local-notification object (for local notifications).

If the application icon is tapped on a device running iOS, the application calls the same method, but furnishes no information about the notification . If the application icon is clicked on a computer running Mac OS X, the application calls the delegate’s applicationDidFinishLaunching: method in which the delegate can obtain the remote-notification payload."

My question is Suppose user got 3-4 Push notifications from provider and all are stored in apple's notification center. If user tapped on notification alert, he/she can easily get the notification data in the app. But if user tapped app icon on iPhone, how to get all the data related of all previous notifications.

Thanks in advance!

5

5 Answers

40
votes

You can't, you will only receive information about the notification that was used to open your app.

So if a user opens your app, and your app has notifications, you will not be able to retrieve them from with in your app.

A work around could be to also keep track of notification on a server and handle this with in the app. Thus the server keeps track on which notification has been read. This is how Facebook does it.

16
votes

To do it in a right way, some conditions must be met:

Your server knows about what your app currently have seen and what notifications it could send once again.

Let's consider only remote notifications. There are three states of app:

  • FOREGROUND:

    • notification appears without user's action:

      func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
          //handle your notification
      }
      

    You can display banner using third party library: BSForegroundNotification

  • BACKGROUND

    • notification appears on the screen. (Note that setting content-available=1 in a push notification can lead to the latest push message being visible once the app icon is pressed, as didReceive... is called).

      //nothing is called in the app, but app icon badge changes
      // OR - if the notification contains the field content-available set to 1 - 
      func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
          //handle your notification
      } 
      
    • user tap on notification

      func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
          //handle your notification
      }           
      
    • user take notification action

      func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
           //handle your notification's action
      }
      

      or

      func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
           //handle your notification's action response info
      }
      
    • user tap app icon

      func applicationDidBecomeActive(application: UIApplication) {
          //fetch pending notifications from server
      }
      
  • NOT RUNNING AT ALL

    • notification appears on the screen.

      //nothing is called in the app, but app icon badge changes
      
    • user tap on notification

      func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
          if let userInfo = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject: AnyObject] {
              //handle your notification
          }
      }
      
    • user take notification action

      func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
           //handle your notification's action
      }
      

      or

      func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
           //handle your notification's action response info
      }
      
    • user tap app icon

      func applicationDidBecomeActive(application: UIApplication) {
          //fetch pending notifications from server
      }
      

How to handle notification?

  1. let notification = WLNotification(userInfo: userInfo)

    Within WLNotification remember to keep current application state when you receive notification. In future you may need it to know where that notification come from.

  2. WLNetworkClient.sharedClient().notificationForIdentifier(notification.identifier)

    Fetch from server details about that notification, and in the same time let it know that you REALLY get that notification, and effected on user's data.

How to fetch all pending notifications?

WLNetworkClient.sharedClient().pendingNotificationsWithCompletionBlock(nil)

Fetch all notifications you missed. in other words, fetch those ones, which were not marked in server as received by you.

Read Limitations of Apple Push Notifications.

See the related questions:

3
votes

I had the same problem: if user clicks on push banner he gets info of push in app, if he clicks on app icon he doesn't get it. You can handle derivative one from it, but with some limits only. Example, if you want to have a badge number from push, you can do it: (Push -> App icon -> App icon badge -> your var)

in AppDelegate

- (void)applicationWillEnterForeground:(UIApplication *)application
{ 
    newMessages = application.applicationIconBadgeNumber;
}
1
votes

Conceptually when application is loaded with clicking alert view presented for Push notification, than application is launched with didReceiveLocalNotification delegate method if your application is in background. At this point applicationDidFinishLaunching delegate method is not called.

When your application is not in background, clicking alert view presented for Push notification will call applicationDidFinishLaunching method.

Hope this clears your understanding between these 2 delegate methods.

-2
votes

You can use this code:

 NSArray *pendingNotifications = [[[UIApplication sharedApplication] scheduledLocalNotifications] sortedArrayUsingComparator:^(id obj1, id obj2)                       {

        if ([obj1 isKindOfClass:[UILocalNotification class]] && [obj2 isKindOfClass:[UILocalNotification class]])
        {
            UILocalNotification *notif1 = (UILocalNotification *)obj1;
            UILocalNotification *notif2 = (UILocalNotification *)obj2;
            return [notif1.fireDate compare:notif2.fireDate];
        }

        return NSOrderedSame;
 }];

 // if there are any pending notifications -> adjust their badge number
 if (pendingNotifications.count != 0)
 {
     //do something
 }