38
votes

I'm reading Apple's docs on

Handling Local and Remote Notifications

and it looks to me to have conflicting statements. Can someone clear up these confusion points? Let's speak strictly of remote notification (versus local) for now.

The docs say that if the action button on the notification is pressed, it calls application:didFinishLaunchingWithOptions and passes in the notification payload. Later it says if the app is running in the foreground, it delivers the notification via application:didReceiveRemoteNotification:. This implies to me that when the app is backgrounded or not running, then application:didFinishLaunchingWithOptions is called. Otherwise, application:didReceiveRemoteNotification: is called.

Later, there is an iOS Note saying the following:

"iOS Note: In iOS, you can determine whether an application is launched as a result of the user tapping the action button or whether the notification was delivered to the already-running application by examining the application state. In the delegate’s implementation of the application:didReceiveRemoteNotification: or application:didReceiveLocalNotification: method, get the value of the applicationState property and evaluate it. If the value is UIApplicationStateInactive, the user tapped the action button; if the value is UIApplicationStateActive, the application was frontmost when it received the notification."

This implies to me that application:didReceiveRemoteNotification: is called both when the app is already foregrounded and if the user presses the action button (or slides the action slider in iOS 5) to foreground/launch the app.

The source of my confusion might be with the first portion where the docs imply the notification payload is sent with the application:didFinishLaunchingWithOptions: method or with a misunderstanding of what a "running" application is (is a backgrounded app considered "running"?). The documentation for application:didReceiveRemoteNotification: states it is called for "running" applications.

So, to summarize, could I get clarification on:

1) Is application:didReceiveRemoteNotification: always called when the app is foregrounded or when the user selects to "act" on the notification? If not, how do we make sense of the iOS Note on determining the Application State being active or inactive?

2) Is a backgrounded app "running", at least in the sense of the docs claiming application:didReceiveRemoteNotification is called for running apps?

3) For completion, is a backgrounded app UIApplicationStateInactive or Active?

2
Can I get a checkmark?ch3rryc0ke

2 Answers

92
votes

The wording here is confusing, especially around the word backgrounding.

When the application is truly not loaded in memory (e,g. when you launch it the splash screen shows up etc), then application:didFinishLaunchingWithOptions is called, and you can get the push notification as follows:

NSDictionary *remoteNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

if(remoteNotif)
{
    //Handle remote notification
}

If the app is loaded in memory and is ACTIVE (e.g. the app is currently open on the device) then only application:didReceiveRemoteNotification: is called.

If the app is loaded in memory but is not ACTIVE and NOT BACKGROUNDING (e.g., you launched the app, then pressed the home button, and waited 10 seconds), and then you click the action button on a push notification, only didReceiveRemoteNotification is called.

You can capture this case as follows:

-(void)application:(UIApplication *)app didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if([app applicationState] == UIApplicationStateInactive)
    {
        //If the application state was inactive, this means the user pressed an action button
        // from a notification. 

    //Handle notification
    }
}
2
votes

As per iOS 9.1 scenario I have tested push notification in Kill mode where my application is not running in any mode at that time if I tap on push notification than the system will call first,

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary *)userInfo{

//your code execution will here.

}

And second method call will be,

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//Your initial code execution.

}

This scenario I have tested in my application.