38

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?

Joey
  • 7,537
  • 12
  • 52
  • 104

2 Answers2

91

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
    }
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
ch3rryc0ke
  • 2,793
  • 1
  • 22
  • 28
  • 2
    Is `didReceiveRemoteNotification` called in the first case you explained? Is it enough to implement my code in both methods you've written? Won't the code run twice? Thanks. – mcont Jun 27 '14 at 20:06
  • 1
    this in incorrect: if you have the notification center visible or control center for instance, the app is considered inactive. do you have any suggestion on how to determine the "becoming active from background" kind ? – dvkch Sep 03 '14 at 15:26
  • also note that the same behavious is related to didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0); – valvoline Jan 21 '15 at 11:37
  • Good answer here which seems to be dealing with some of the other issues: http://stackoverflow.com/questions/5835806/check-if-ios-app-is-in-background basically checking if the app is inactive of in the background: if (state == UIApplicationStateBackground || state == UIApplicationStateInactive). A bit of work with this could probably satisfy all the different cases – sam_smith Mar 26 '15 at 23:46
  • What if I tap the home button, and the send notification. I see the notification, but I choose to tap the app icon, instead of the notification. My app will have no idea of the notification? – nr5 Jun 09 '17 at 07:36
2

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.

Gautam Sareriya
  • 1,833
  • 19
  • 30