7

In my current project I have a push notification. When I tap the app icon I want to get the received notification from the launch options object, but it always returns nil:

NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
Markus Amalthea Magnuson
  • 8,415
  • 4
  • 41
  • 49
Jaydeep Chauhan
  • 309
  • 1
  • 3
  • 12
  • can u show the whole code or in which method you have tried to get userinfo? – Vizllx May 18 '15 at 07:44
  • in "- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}" and "- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions" – Jaydeep Chauhan May 18 '15 at 08:02

2 Answers2

7

You can't detect that case, because application is not open using push notification (it has been open via app icon).
Try to open application by swiping push notification.

EDIT:

If you want to be invoked for push notification (via background fetch, when your application is not active) you need to ask your backend developer to set "content-available": 1 in push notification.

After that -application:didReceiveRemoteNotification:fetchCompletionHandler: will be invoked (when push-notification arrives), so you can save the payload into a file and then when application will be open, you can read the file and take actions.

- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"#BACKGROUND FETCH CALLED: %@", userInfo);
    // When we get a push, just writing it to file
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"userInfo.plist"];

    [userInfo writeToFile:filePath atomically:YES];
    completionHandler(UIBackgroundFetchResultNewData);
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Checking if application was launched by tapping icon, or push notification
    if (!launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"userInfo.plist"];

        [[NSFileManager defaultManager] removeItemAtPath:filePath
                                                   error:nil];
        NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:filePath];
        if (info) {
            // Launched by tapping icon
            // ... your handling here
        }
    } else {
        NSDictionary *info = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
        // Launched with swiping
        // ... your handling here
    }
    return YES;
}

Also don't forget to enable "Remote notifications" in "Background Modes" enter image description here

l0gg3r
  • 8,864
  • 3
  • 26
  • 46
  • open application by swiping push notification is working but i also want same thing on app icon tap – Jaydeep Chauhan May 18 '15 at 08:05
  • @ l0gg3r after enabled the remote notifications background mode facing same problem in ios8 device also.. – Jaydeep Chauhan May 18 '15 at 09:01
  • @JaydeepChauhan you're right, the dictionary will be nil, but you will be invoked when push notification arrives, so you can save the payload into file, and when user opens your application read the file and delete it. – l0gg3r May 18 '15 at 09:11
  • thanks for your fast reply.. can you give me any demo for that, so its easy for me to understand. – Jaydeep Chauhan May 18 '15 at 09:21
  • When app is inactive notification is not receiving in - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler.I have done the same thing as mentioned above.Kindly suggest/guide me. – Mehmood Hassan Feb 24 '16 at 12:51
  • @MehmoodHassan did your backend dev put "content-available": 1 in push notification body? – l0gg3r Feb 25 '16 at 16:50
  • When app got killed then it will not invoke didreceiveremotenotification method.Didreceiveremotenotification method will be invoked only in three cases 1)When app is in foreground,2)When app is in background mode,3)When user swipe/touch push notification. – Mehmood Hassan Feb 26 '16 at 11:07
  • @l0gg3r have you tested it when app got killed.? – Mehmood Hassan Feb 26 '16 at 11:17
  • Is your answer and [this answer](https://stackoverflow.com/a/21611009/5175709) both doing the same thing? – mfaani Jun 27 '17 at 19:20
  • @Honey nop, mine actually wakes up application and gives it a chance to run some code. – l0gg3r Jul 06 '17 at 11:23
  • I'm only asking about after the user has tapped. It seems your answer using `UIApplicationLaunchOptionsRemoteNotificationKey` handles the tapping on notification right from the didFinishLaunching but the other answer, just sends passes the notification by virtually invoking the `didReceiveNotification` And then handles it there ie 2 places but evetnually same handling. Am I wrong? – mfaani Jul 06 '17 at 13:05
  • @Honey right, but it's hacky, so you are losing the event if push was received/swiped or user just opened the application – l0gg3r Jul 07 '17 at 14:53
  • So you mean if we do it your way... You know **for sure** that app was launched (from suspended/terminated state) and *if needed* separate that logic from just simply calling tapping/receiving notification. Luckily in iOS 10 there is a much higher separation of concerns that is you simply implement `- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler`. – mfaani Jul 07 '17 at 15:13
  • Having that said, I think the other solution is better. Why? Because it separates app launch logic from opening from notification. Yours is kinda mixed. You're offering a solution to a problem that shouldn't exist. Or should be addressed through better modular code. I mean I can't think of any logic that would be specific to **App Launch through notification**. You either have **App launch** logic or **App notification receiving** logic or **notification tapped** logic. What do you think? – mfaani Jul 07 '17 at 15:13
6

When you launch the application from a PUSH NOTIFICATION ACTION, [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey] will return you the push notification payload (in dictionary format). When I say push notification action, it means either tapping the push notification from action center or from the push notification alert dialog (Depending on the device settings, push notification delivery mechanism varies).

If you launch the application by tapping the APP ICON, [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey] always returns nil. Because, it hasn't been launched from any kind of push notification.

Rashmi Ranjan mallick
  • 6,390
  • 8
  • 42
  • 59