locked
How to properly handle push notifications in the background in Xamarin iOS (10-13) RRS feed

  • Question

  • User44776 posted

    Hi All,

    I need to trigger a web api call when a push notification comes in but my app doesn't trigger the DidReceiveRemoteNotification override when it is in the background. What am I missing?

    According to Apple's documentation here https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application
    "The system calls this method when your app is running in the foreground or background." and "If the user opens your app from the system-displayed alert, the system may call this method again".

    But the 1st statement doesn't seem to be the case as the method is only triggered when I launch the app via the notification, but never triggered when the notification was received. I need to do this api call in the background so the user sees the updated data when they open the app regardless if they launch the app via the notification or via the app icon. I'm pretty sure this used to work in the earlier versions of iOS, but doesn't seem to work now (or was I dreaming?).

    I already have 'content-available': 1 in my push notification as suggested here https://docs.microsoft.com/en-us/xamarin/ios/app-fundamentals/backgrounding/ios-backgrounding-techniques/updating-an-application-in-the-background#remote-notifications-ios-7-and-greater But still no luck.

    I have already enabled background modes (background fetch and remote notifications)

    I have this in my FinishedLaunching override in AppDelegate: UIApplication.SharedApplication.RegisterForRemoteNotifications(); UNUserNotificationCenter.Current.Delegate = this;

    And I have below overrides in my AppDelegate:

    public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
            {
                myWebApiCall();
                completionHandler(UIBackgroundFetchResult.NewData);
            }
    
    public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
            {
                myWebApiCall();
            }
    

    Please help. Thanks in advance.

    Tuesday, October 22, 2019 11:24 AM

Answers

  • User44776 posted

    Ok so I finally got it working!

    DidReceiveRemoteNotification is now triggered when a push notification comes in and the app is in the foreground, int the background, and sometimes even after the app was forcibly closed.

    1. Enabled background modes (background fetch and remote notifications) in the plist

    2. Added these in my FinishedLaunching override in AppDelegate: UIApplication.SharedApplication.RegisterForRemoteNotifications(); UNUserNotificationCenter.Current.Delegate = this;

    3. DidReceiveRemoteNotification

    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")] public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action completionHandler) { completionHandler(UIBackgroundFetchResult.NewData);

    if (application.ApplicationState == UIApplicationState.Active)
            {
                MyLogging("Debug", "Foreground > DidReceiveRemoteNotification");
                Task.Run(async () =>
                 {
                    await System.Threading.Tasks.Task.Delay(1000);
                         callMyForegroundMethod();
                 }); 
    }
    else if (application.ApplicationState == UIApplicationState.Background)
    {
        MyLogging("Debug", "Background > DidReceiveRemoteNotification");
            //the web api call goes into "Network connection lost" error if I don't add the delay.
            Task.Run(async () =>
                 {
                    await System.Threading.Tasks.Task.Delay(1000);
                         callBackgroundSyncWebApiMethod();
                 });
     }
    else if (application.ApplicationState == UIApplicationState.Inactive)
    {
        MyLogging("Debug", "Inactive > DidReceiveRemoteNotification");
         //the web api call goes into "Network connection lost" error if I don't add the delay.
        Task.Run(async () =>
        {
            await System.Threading.Tasks.Task.Delay(1000);
            callBackgroundSyncWebApiMethod();
        });
     }
    

    }

    1. Push notification: { "aps" : { "content-available" : 1, "alert" : { "title" : "My push notification title", "body" : "My push notification body" }, "badge" : 99 } }

    Note: According to Apple's documentation in https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

    To support a background update notification, make sure that the payload’s aps dictionary includes the content-available key with a value of 1. If there are user-visible updates that go along with the background update, you can set the alert, sound, or badge keys in the aps dictionary, as appropriate.

    Hope this helps others in the same situation.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, October 23, 2019 8:58 AM

All replies

  • User369978 posted

    To enable silent Remote Notification , we should do

    1. Make sure your app has the "Remote notifications" background mode enabled in the plist.
    2. The notification payload cannot contain an alert, otherwise it's not "silent". However, you can include a custom key/value in a "silent" notification payload.

    Refer https://forums.xamarin.com/discussion/comment/43367/#Comment_43367

    Tuesday, October 22, 2019 2:20 PM
  • User44776 posted

    @ColeX : Thanks, but does this mean we should always be sending silent push notifications if we need to do something in the background? And since silent notifications doesn't have the alert, we'll need to create a local notification ourselves inside DidReceiveRemoteNotification if the app is in the background?

    If above is the case: 1. I think this would be a problem when the app was forced-quit as iOS would stop raising the DidReceiveRemoteNotification event for silent notifications. 2. Silent notifications are rate-limited, which means there's a chance that your user won't get notified when he should have been notified because APNS delays the silent notification. Unless maybe our server sends out 2 type of notifications every time? E.g. Alert to trigger the notification banner and Silent notification to trigger the background sync?

    Tuesday, October 22, 2019 10:48 PM
  • User44776 posted

    Ok so I finally got it working!

    DidReceiveRemoteNotification is now triggered when a push notification comes in and the app is in the foreground, int the background, and sometimes even after the app was forcibly closed.

    1. Enabled background modes (background fetch and remote notifications) in the plist

    2. Added these in my FinishedLaunching override in AppDelegate: UIApplication.SharedApplication.RegisterForRemoteNotifications(); UNUserNotificationCenter.Current.Delegate = this;

    3. DidReceiveRemoteNotification

    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")] public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action completionHandler) { completionHandler(UIBackgroundFetchResult.NewData);

    if (application.ApplicationState == UIApplicationState.Active)
            {
                MyLogging("Debug", "Foreground > DidReceiveRemoteNotification");
                Task.Run(async () =>
                 {
                    await System.Threading.Tasks.Task.Delay(1000);
                         callMyForegroundMethod();
                 }); 
    }
    else if (application.ApplicationState == UIApplicationState.Background)
    {
        MyLogging("Debug", "Background > DidReceiveRemoteNotification");
            //the web api call goes into "Network connection lost" error if I don't add the delay.
            Task.Run(async () =>
                 {
                    await System.Threading.Tasks.Task.Delay(1000);
                         callBackgroundSyncWebApiMethod();
                 });
     }
    else if (application.ApplicationState == UIApplicationState.Inactive)
    {
        MyLogging("Debug", "Inactive > DidReceiveRemoteNotification");
         //the web api call goes into "Network connection lost" error if I don't add the delay.
        Task.Run(async () =>
        {
            await System.Threading.Tasks.Task.Delay(1000);
            callBackgroundSyncWebApiMethod();
        });
     }
    

    }

    1. Push notification: { "aps" : { "content-available" : 1, "alert" : { "title" : "My push notification title", "body" : "My push notification body" }, "badge" : 99 } }

    Note: According to Apple's documentation in https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

    To support a background update notification, make sure that the payload’s aps dictionary includes the content-available key with a value of 1. If there are user-visible updates that go along with the background update, you can set the alert, sound, or badge keys in the aps dictionary, as appropriate.

    Hope this helps others in the same situation.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, October 23, 2019 8:58 AM
  • User369978 posted

    Great! Could you mark your solution as answer to help others ?

    Wednesday, October 23, 2019 9:54 AM