iosapple-push-notificationsmaui

Maui .net7 ios APN Push notifications - UNUserNotificationCenterDelegate functions not getting hit in background


I have a maui .net7 iOS application and I can't seem to get the push notifications to work quite right when the app is not in the foreground. (Note, I'm NOT using Firebase.)

I have been following Microsoft's documentation: https://learn.microsoft.com/en-us/xamarin/ios/platform/user-notifications/enhanced-user-notifications?tabs=windows

and this code example here https://github.com/xamarin/xamarin-forms-samples/blob/97d6825e2ba3aa64667695f3c43224c9171e51e5/LocalNotifications/LocalNotifications/LocalNotifications.iOS/iOSNotificationReceiver.cs

Scenario 1 When the app is in the foreground when a push notification comes in, the notification is recieved in the appDelegate's ReceivedRemoteNotification function. I then put the notification information into my local database, and display a local notification using the plugin Plugin.LocalNotification; This notification displays correctly and when clicked the application will open a particular view.

All good here.

Scenario 2 When the app is running but in the background, the same occurs as when in the foreground. The notification is logged in the database, a local notification is shown that does the correct action when clicked.

However, it's ALSO showing another "default" notification that does nothing when clicked.

I need to prevent this "default" notification from showing. Nowhere in my code do I call the code to add the nofication: UNUserNotificationCenter.Current.AddNotificationRequest(request, OnNotificationError);

Scenario 3 When the app is not running and a notification comes in, the app shows the "default" notification that does nothing when clicked, and the notification is not logged in my database.

I need to ensure the code to add the notification to the database runs. When the app is closed it won't need to open a particular view as the app will require the user to log in, but I do need the app to present the notification in the GUI so they can still reach the correct view.

Debugging on the mac iOS simulator is not working for me (notifications are not appearing at all), so I have been trying to use appcenter analytics logUsage() to determine what code is getting hit. It seems the logging is not occurring while the app is in the background, so its difficult to say if the UNUserNotificationCenterDelegate's WillPresentNotification and DidReceiveNotificationResponse code it getting hit or not. Seems like they are not.

AppDelegate.cs

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
    UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate(); //my custom class

    // ... code to register to register for notifications and check permission - works, removed for example
}


[Export("application:didReceiveRemoteNotification:")]
public void ReceivedRemoteNotification(UIApplication application, NSDictionary notification) 
{
    //code to process notification, add to DB and display the local notification starts here. 
    //Runs correctly when app is in foreground
}

UserNotificationCenterDelegate.cs

public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate, IUNUserNotificationCenterDelegate
{
    [Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
    public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
    {
        //attempted adding to DB here for when the application is not running, did not work. Not sure this code is ever hit
        completionHandler(UNNotificationPresentationOptions.None); //this should tell the app not to show the default notification
    }

    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
    public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
    {
        //this should be hit when the default notification is clicked. Not sure this is ever hit

        if (!response.IsDismissAction)
        {
            //run code to open the correct view
        }
        completionHandler();// Inform caller it has been handled
    }

}

Can anyone tell me:

  1. where the remote notifications come into the app while in the background, so I can ensure the data is written to the DB. (does not seem to be AppDelegate's ReceivedRemoteNotification)
  2. where I can determine if the app should display the "default" notification when the app is in the background (UNUserNotificationCenterDelegate's WillPresentNotification isn't doing it)
  3. where I should write the code to open the correct view when the default notification is clicked (UNUserNotificationCenterDelegate's DidReceiveNotificationResponse isn't doing it. Might not be required if I can get #1 & 2 working correctly)

Many thanks!

Update:

I discovered another function not mentioned in the Microsoft documentation:

[Export("application:didReceiveRemoteNotification:fetchCompletionHandler:")]
public void DidReceiveRemoteNotification(UIApplication application, NSDictionary notification, Action<UIBackgroundFetchResult> completionHandler)
{
    //code to write the notification to the DB and display the local notification
    
    completionHandler(UIBackgroundFetchResult.NewData);
}

the system calls this method when your app is running in the foreground or background. Tells the app that a remote notification arrived that indicates there is data to be fetched. Use this method to process incoming remote notifications for your app.

See apple's documentation: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application

Also mentioned here: https://github.com/dotnet/maui/issues/6259

Now when the app is not running, I can write the notification into the DB and show the local notification!

It also shows the default notification; I still need to determine how to prevent this notification from appearing when the app is in the background or not running.


Solution

  • You can try this code -

    public func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {   
                
        /// add code before this comment to get notification data and update in database
        UNUserNotificationCenter.current().removeAllDeliveredNotifications()
        completionHandler(.noData)
        /// write your code after this comment to show local notification
    }
    

    this should hide the default notification in case app is in background or not opened

    Let me know if this works for you. Happy to help :)