Remote Notification - response.IsDefaultAction called and crashes when app is in inactive state

gtodd876gtodd876 Member ✭✭

When the user taps on a remote notification, I am pushing a specific detail view controller on my Home NavController or selecting a specific TabBarController index based off of some custom keys in the payload of the remote notification. This is all working great when the app in the background.

public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
int id;
if (response.IsDefaultAction)
{
var userInfo = response.Notification.Request.Content.UserInfo;

        topicValue = userInfo.ObjectForKey(new NSString("topic")).ToString();
        string linkType = userInfo.ObjectForKey(new NSString("linktype")).ToString();
        string linkPost = userInfo.ObjectForKey(new NSString("linkpage")).ToString();

        var window = UIApplication.SharedApplication.KeyWindow;
        var vc = window.RootViewController as UITabBarController;

     // .. a bunch of conditional logic to decide which view controller to push after the app comes back to the foreground 
    var homeNavController = vc.ChildViewControllers[0] as UINavigationController;
        homeNavController.PushViewController(detailViewController, true);
        vc.SelectedIndex = 0;
    }
        completionHandler();

}

This works great when the app in the background.

Before I added this code, when the app was inactive, tapping on the remote notification would cause the app to open up normally to the home view controller.

After adding that logic, that app crashes after the splash screen if the user taps a remote notification when the app is inactive.

This was confusing because after researching to topic on these forums as well as Stack Overflow it sounded as if FInishedLaunching and accessing that method's launchOptions parameter was the way to deal with to deal with the user tapping on remote notification when the app is inactive.

Microsoft's App Center crash logs also confirm that the app is crashing in the DidReceiveNotificationResponse method within my if (response.IsDefaultAction) conditional logic. Yes, the is also when the app is inactive and the user taps the notification. (IsDefaultAction)

This is tough to debug because Visual Studio for Mac's debug mode stops as soon as you close out your app manually. At this point I have to make a code change, deploy the app to my phone, close out the app, send a remote notification, tap on it and when app crashes, then check the crash log on app center. Is there a better way?

Any help would be greatly appreciated :smile:

Best Answer

  • gtodd876gtodd876 ✭✭
    Accepted Answer

    I finally got it working when the app is in the background and if the app had been closed out manually. I thought I would post my solution here in case it helps anybody else.

    In both cases (app closed or in background) DidReceiveNotificationResponse is called in the AppDelegate when the user taps the notification.

                public class MyNotificationCenterDelegate : UNUserNotificationCenterDelegate
                {
                    UIViewController detailViewController;
                    public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
                    {
                        UIApplication application = UIApplication.SharedApplication;
                        if (response.IsDefaultAction)
                        {
                            var userInfo = response.Notification.Request.Content.UserInfo;
    
                            string linkType = userInfo.ObjectForKey(new NSString("linktype")).ToString();
                            string linkPost = userInfo.ObjectForKey(new NSString("linkpage")).ToString();
    
                //I'm using Xamarin.Essentials package to manage my User Defaults Key Value pairs with the
                // `Preferences method. Then I can see if those keys are set or not in `ViewDidLoad` in 
                // my HomeViewController. This covers the case if the app had been closed 
                //when the notification is tapped.
    
                            Preferences.Set("linkType", linkType);
                            Preferences.Set("linkPost", linkPost);
    
                            var window = UIApplication.SharedApplication.KeyWindow;
                            var tc = window.RootViewController as UITabBarController;
    
                            if(tc != null) 
                {
                //this is essential. if app was in background then `tc != null` then this logic can run here.
                //If the app was closed and `tc == null` then this logic will be carried out at the end of my 
                // ViewDidLoad method in my HomeViewController instead of this method.
    
                               // carry out your logic for your app to either push a view controller or
                   // select a TabBarController index ...
    
                           //if you are pushing a detail view controller on your Home Navigation Controller
                                    var homeNavController = tc.ChildViewControllers[0] as UINavigationController;
                                    homeNavController.PushViewController(detailViewController, true);
    
                                    tc.SelectedIndex = 0; //select my HomeViewController via TabBarController index
                            }
                        }
    
                        completionHandler();
                    }
    

    So if tc your TabBarController is null then that means your app was closed and is now being opened by tapping on the notification. I carried out the same logic at the end of my ViewDidLoad in my HomeViewController which covers the case that the app had been manually closed.

    Some things to remember are to Preferences.Remove("YourKey"); in the right places to clear out those values after you have navigated to the correct view controller.

Answers

  • gtodd876gtodd876 Member ✭✭
    Accepted Answer

    I finally got it working when the app is in the background and if the app had been closed out manually. I thought I would post my solution here in case it helps anybody else.

    In both cases (app closed or in background) DidReceiveNotificationResponse is called in the AppDelegate when the user taps the notification.

                public class MyNotificationCenterDelegate : UNUserNotificationCenterDelegate
                {
                    UIViewController detailViewController;
                    public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
                    {
                        UIApplication application = UIApplication.SharedApplication;
                        if (response.IsDefaultAction)
                        {
                            var userInfo = response.Notification.Request.Content.UserInfo;
    
                            string linkType = userInfo.ObjectForKey(new NSString("linktype")).ToString();
                            string linkPost = userInfo.ObjectForKey(new NSString("linkpage")).ToString();
    
                //I'm using Xamarin.Essentials package to manage my User Defaults Key Value pairs with the
                // `Preferences method. Then I can see if those keys are set or not in `ViewDidLoad` in 
                // my HomeViewController. This covers the case if the app had been closed 
                //when the notification is tapped.
    
                            Preferences.Set("linkType", linkType);
                            Preferences.Set("linkPost", linkPost);
    
                            var window = UIApplication.SharedApplication.KeyWindow;
                            var tc = window.RootViewController as UITabBarController;
    
                            if(tc != null) 
                {
                //this is essential. if app was in background then `tc != null` then this logic can run here.
                //If the app was closed and `tc == null` then this logic will be carried out at the end of my 
                // ViewDidLoad method in my HomeViewController instead of this method.
    
                               // carry out your logic for your app to either push a view controller or
                   // select a TabBarController index ...
    
                           //if you are pushing a detail view controller on your Home Navigation Controller
                                    var homeNavController = tc.ChildViewControllers[0] as UINavigationController;
                                    homeNavController.PushViewController(detailViewController, true);
    
                                    tc.SelectedIndex = 0; //select my HomeViewController via TabBarController index
                            }
                        }
    
                        completionHandler();
                    }
    

    So if tc your TabBarController is null then that means your app was closed and is now being opened by tapping on the notification. I carried out the same logic at the end of my ViewDidLoad in my HomeViewController which covers the case that the app had been manually closed.

    Some things to remember are to Preferences.Remove("YourKey"); in the right places to clear out those values after you have navigated to the correct view controller.

Sign In or Register to comment.