didReceiveRemoteNotification: fetchCompletionHandler: open from icon vs push notification
Asked Answered
R

3

54

I'm trying to implement background push notification handling, but I'm having issues with determining whether the user opened the app from the push notification that was sent as opposed to opening it from the icon.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    //************************************************************
    // I only want this called if the user opened from swiping the push notification. 
    // Otherwise I just want to update the local model
    //************************************************************
    if(applicationState != UIApplicationStateActive) {
        MPOOpenViewController *openVc = [[MPOOpenViewController alloc] init];
        [self.navigationController pushViewController:openVc animated:NO];
    } else {
        ///Update local model
    }

    completionHandler(UIBackgroundFetchResultNewData);
}

With this code, the app is opening to the MPOOpenViewController regardless of how the user opens the app. How can I make it so that the view controller is only pushed if they open the app from swiping the notification?

With the same code, this worked on iOS 6, but with the new iOS 7 method, it doesn't behave how I want it to.

Edit: I'm trying to run the app on iOS 7 now, and we are not supporting any version prior to iOS 7. I used this same exact code in the iOS 6 version of the method (without the completion handler) and it behaved the way I'd expect it to. You'd swipe the notification and this would get called. If you opened from the icon, the method would never be called.

Rabe answered 28/2, 2014 at 2:50 Comment(8)
It's seems fine. When you opened the app from icon this method never be called. So exactly what is the problem you are facing or what else you want to achieve ?Silures
@ArpitKumarKulshrestha that's not true. Since the app supports background remote notifications, this method is called while the app is still in the background. For example, if I put a break point here and close the app. Then when I receive the push, it hits the breakpoint with the app still closed. That did not happen in iOS6Rabe
In your Question line "With the same code, this worked on iOS 6, but with the new iOS 7 method, it doesn't behave how I want it to.". Specify in which iOS it is running ?Silures
You can't do this in iOS 6. #20488390Silures
I'm running this on iOS 7. We are not supporting anything before iOS 7Rabe
I think you should check mark the push notification background mode to enable it. OR Enter in Plist to enable background mode for push notification. I think you aware about that.Silures
@Arpit You're missing my question entirely. This method is being called every time I get a push, like it should. The issue is that in the background, a new view is being pushed onto the navigation stack. I'd only like that to happen if the user swipes from the notification (they expect to see the contents right away). If they hit the icon, they should be taken to the home screen, where we have a badge telling the user that there is new content for them in their feed.Rabe
Same issue is getting in ios 10 ,in 9.3 it is working fine and below solutions are failing in ios 10Clisthenes
R
88

Ok I figured it out. The method is actually called twice (once when it receives the push, and once when the user interacts with the icon or the notification).

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    if(application.applicationState == UIApplicationStateInactive) {

        NSLog(@"Inactive");

        //Show the view with the content of the push

        completionHandler(UIBackgroundFetchResultNewData);

    } else if (application.applicationState == UIApplicationStateBackground) {

        NSLog(@"Background");

        //Refresh the local model

        completionHandler(UIBackgroundFetchResultNewData);

    } else {

        NSLog(@"Active");

        //Show an in-app banner

        completionHandler(UIBackgroundFetchResultNewData);

    }
}

Thanks Tim Castelijns for the following addition:

Note: the reason it's called twice is due to the Payload having content_available : 1. If you remove the key and its value, then it will only run upon tapping. This will not solve everyone's problem since some people need that key to be true

Rabe answered 28/2, 2014 at 3:54 Comment(9)
Thank you so much!!!! This was VERY helpful!!!! Anyone who is stuck with figuring out how to implement background remote notifications, see this page: developer.xamarin.com/guides/cross-platform/…Chrisom
Just a little optimization. If you are calling completionHandler(UIBackgroundFetchResultNewData); in each conditional, you can call it unconditionally and remove two of these lines.Carnivore
The problem with the UIApplicationStateInactive state is that it happens not only if the app is being opened by user's interaction with the notification but also when the app is in the Inactive state, e.g.: when a sms/call is received, Notification Center is shown or Control Center. Therefore, it results in false positives where it navigates to the view in the cases mentioned above.Checklist
Thanks a lot for writing that you get TWO calls for each notification! Saved my day :) However, remember to enable Background fetch and Remote notifications in your project -> Capabilities -> Background ModesDeep
Note: the reason it's called twice is due to the PN having content_available=true. If you remove it or set it to false, it will only run once. This will not solve everyone's problem since some people need that key to be trueBekha
Tim, i have to have the content available set to false otherwise nothing is sent. any suggestions? i am also unable to get notifications while the app is completely switched off. could this be related?Mellisamellisent
@TomKraina as for when your app is opened after a dismissed message or finished call, your state would be: UIApplicationStateInactive...OK. Understood. But I don't get why at that moment you would get a callback from your didReceiveRemoteNotification method!? I mean you're not receiving a notification at that moment. I don't understand the flow you're talking about.Direct
could me tell me how to start with it @Mike VStafani
content_available : 0 fixed my issue. I am checking it on 2018 and it saved my life :) thanksRuben
A
12

@MikeV's solution in Swift 3 (but with switch statement):

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

    switch application.applicationState {

    case .inactive:
        print("Inactive")
        //Show the view with the content of the push
        completionHandler(.newData)

    case .background:
        print("Background")
        //Refresh the local model
        completionHandler(.newData)

    case .active:
        print("Active")
        //Show an in-app banner
        completionHandler(.newData)
    }
}
Abreaction answered 7/3, 2017 at 15:30 Comment(0)
M
9

@MikeV's solution in Swift 2:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {

    if(application.applicationState == UIApplicationState.Inactive)
    {
        print("Inactive")
        //Show the view with the content of the push
        completionHandler(.NewData)

    }else if (application.applicationState == UIApplicationState.Background){

        print("Background")
        //Refresh the local model
        completionHandler(.NewData)

    }else{

        print("Active")
        //Show an in-app banner
        completionHandler(.NewData)
    }

}
Michelsen answered 24/5, 2016 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.