maui icon indicating copy to clipboard operation
maui copied to clipboard

MAUI .net7 / .net8 ios push notifications not received in DidReceiveRemoteNotification

Open aleks42 opened this issue 2 years ago • 10 comments
trafficstars

Description

Can not receive push notification in maui application on iOS when the application is running (in foreground). Looks like everything works except receiving push notifications in app. I successfully register for notifications and get push token.

public class AppDelegate : MauiUIApplicationDelegate, IUNUserNotificationCenterDelegate
{
    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        RegisterForRemoteNotifications(app);
        return base.FinishedLaunching(app, options);
    }

    private void RegisterForRemoteNotifications(UIApplication app)
    {
            if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
            {
                // iOS >= 10
                UNUserNotificationCenter.Current.RequestAuthorization(
                    UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound, 
                    (granted, error) => 
                    {
                        if (error != null) {}// log error.DebugDescription
                    });

                UNUserNotificationCenter.Current.Delegate = this; // implemented in AppDelegate methods: WillPresentNotification and DidReceiveNotificationResponse from IUNUserNotificationCenterDelegate
            }
            else
            {
                var settings = UIUserNotificationSettings.GetSettingsForTypes(
                    UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, 
                    null);
                UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
            }

            app.RegisterForRemoteNotifications();
    }

    [Export("application:didReceiveRemoteNotification:fetchCompletionHandler:")]
    public void DidReceiveRemoteNotification(UIKit.UIApplication application, NSDictionary userInfo, Action<UIKit.UIBackgroundFetchResult> completionHandler)
    {
        ...
        completionHandler(UIBackgroundFetchResult.NoData);
    }

    [Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
    public void RegisteredForRemoteNotifications(UIKit.UIApplication application, NSData deviceToken)
    {
        var deviceTokenHex = ByteArrayHelper.BytesToHex(deviceToken?.ToArray());
        ...
    }

    [Export("application:didFailToRegisterForRemoteNotificationsWithError:")]
    public void FailedToRegisterForRemoteNotifications(UIKit.UIApplication application, NSError error)
    {
        // error.DebugDescription
        ...
    }

    [Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
    public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
    {
        // notification?.Request?.Content?.UserInfo
        ...
    }

    // user clicked at presented notification
    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
    public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
    {
        ...
    }

...
}

Steps to Reproduce

  1. Create new project.
  2. Setup push notifications on the apple side (certificates etc)
  3. Implement notifications like in description In app:
  4. Register for notifications
  5. Get push token
  6. Send notification to device when app is in background - works fine!
  7. Send notification to device when app is in foreground - nothing happens

Link to public reproduction project repository

No response

Version with bug

7.0.96

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

iOS 17.0.3

Did you find any workaround?

no

Relevant log output

No response

aleks42 avatar Oct 13 '23 14:10 aleks42

I'm experiencing a similar issue and was wondering if the development team had any input that could help?

ccarpenter04 avatar Oct 19 '23 15:10 ccarpenter04

Can you try doing this, this is what fixed the issue for me Issue 194 - Plugin.Firebase.CloudMessaging

omxie avatar Oct 23 '23 20:10 omxie

I don't use firebase. I don't quite understand, is it possible to "catch" an incoming push notification if you subscribe to "iOS.WillFinishLaunching" ? Or it works with firebase plugin only ?

aleks42 avatar Oct 23 '23 20:10 aleks42

Please ignore the above comment, for some reason I assumed that you were using the plugin.

As to your issue, in iOS when the application is in the foreground, you'll need to handle the notification because iOS will not automatically display the notification to the user. The easiest way would be to create a local notification.

omxie avatar Oct 26 '23 01:10 omxie

@aleks42 Any news here? Did you found a solution? I have same problem. Notification in background is working, but not in foreground. We also do not use firebase. We use Azure Notification Hub and Microsoft do not provide a plugin.

dasflaigsi avatar Dec 18 '23 08:12 dasflaigsi

To tell the truth, I've come to the conclusion that this feature doesn't work. In my case, there is a relatively short time when a push notification can appear in the foreground. I just call the backend several times on a timer and show a notification if new ones appear. I haven't checked how it works in .net 8 yet.

aleks42 avatar Dec 18 '23 11:12 aleks42

Did anybody get didReceiveRemoteNotification to work in MAUI .Net8? I can't get the method to be triggered in AppDelegate, no matter what I try. WillPresentNotification() is triggered when the app is in foreground, but I also need to handle silent notifications while the app is backgrounded.

umike72 avatar May 01 '24 04:05 umike72

Did anybody get didReceiveRemoteNotification to work in MAUI .Net8? I can't get the method to be triggered in AppDelegate, no matter what I try. WillPresentNotification() is triggered when the app is in foreground, but I also need to handle silent notifications while the app is backgrounded.

I have the same issue. :( Any solution for .net 8?

jlacacioYouPana avatar May 13 '24 19:05 jlacacioYouPana

Did anybody get didReceiveRemoteNotification to work in MAUI .Net8? I can't get the method to be triggered in AppDelegate, no matter what I try. WillPresentNotification() is triggered when the app is in foreground, but I also need to handle silent notifications while the app is backgrounded.

It doesn't even work for me in the foreground, did you do anything special for that? thanks

filyXplor avatar May 21 '24 12:05 filyXplor

Same for me, i try using 2 plugin, Plugin.Firebase.CloudMessaging and with Plugin.FirebasePushNotification but no one works, even if all the code works and i am able to receive the FCM token

REDECODE avatar May 23 '24 13:05 REDECODE

same issue, any solution?

jeyamani123 avatar Jun 11 '24 16:06 jeyamani123

I've ended up implementing a workaround. Instead of relying on didReceiveRemoteNotification to receive data payload I've implemented am API service that I query on application activation to retrieve whatever data the application needs.

This means that when the user starts the app or when he taps on a visible notification that triggers the app to start, the application retrieves the data it needs...

umike72 avatar Jun 11 '24 23:06 umike72

Any update on this issue?

SergTomcat avatar Jul 01 '24 11:07 SergTomcat

I've also faced with the same issue. Any updates on it?

odil-giyasov avatar Jul 02 '24 12:07 odil-giyasov

Any updates on this? Did anyone manage to find a workaround that doesn't imply any backend changes? The project that I am working on really needs background (silent) notifications because the notification needs to be displayed by the app in the user's language, information that is not available on the backend.

FacemSoft avatar Aug 19 '24 09:08 FacemSoft

Do you know why my program crashes when I get to the line in debug UNUserNotificationCenter.Current.Delegate = this; It seems like I implemented everything, but it doesn't throw any exceptions, it just doesn't work anymore

Cholponai02 avatar Aug 23 '24 05:08 Cholponai02

well, I found out that in debug mode completely removing the entilements.pList file the debug works again here to run on real devices in debug, but to publish in test it is necessary to add and generate the package, it seems that even the configuration determined only in realese in cs is no use, just the fact of having the file in the iOS folder affects in debug, and it doesn't allow, I managed to get pushes with app closed and in the background the notifications, and apparently pass through didReceiveNotificationResponse and didReceiveIncomingPushWithPayload in release, but in debug nothing.. I can leave the app in the background that only in payload works in normal notifications no.. in the case in didReceiveNotificationResponse debug mode still doesn't work, only in realese, but for me what made debug work in real device was to remove entilements file from the project even though it is not set in cs.proj

work for me in realese mode, but not in debug mode (does not work and does not run device if there is an entilements file in the iOS folder)

public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
    public async override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler){
}
}

Working for my in debug mode and realese mode from voip

[Register("PushRegistryDelegate")]
public class PushRegistryDelegate : PKPushRegistryDelegate
{
[Export("pushRegistry:didReceiveIncomingPushWithPayload:forType:withCompletionHandler:")]
public override void DidReceiveIncomingPush(PKPushRegistry registry, PKPushPayload payload, string type, Action completionHandler)
{
}
}

in AppDelegate....

 public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
 {
     instance = this;
     UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();

     var voipRegistry = new PKPushRegistry(DispatchQueue.MainQueue);
     voipRegistry.Delegate = new PushRegistryDelegate();
     voipRegistry.DesiredPushTypes = new NSSet(new string[] { PKPushType.Voip });
   
     return base.FinishedLaunching(application, launchOptions);
 }

GuilhermeHeibelTech avatar Aug 24 '24 20:08 GuilhermeHeibelTech

Here's what I've got goin on in iOS and it works great. Note I am using FCM so if you're not just ignore things that begin with Messaging. Currently running .NET 8 for iOS and Android. Hope this helps somebody.

Another note: WillPresentNotification in the NotificationDelegate is where I am handling (to not show) notifications in the foreground.

Here are the packages being used.

<ItemGroup> <!-- This is used for both iOS and Android -->
       <PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
</ItemGroup>

<!-- Was getting a lot of Android build errors but this combination of nugets seems to be the fix -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-android'">
	<PackageReference Include="Xamarin.AndroidX.Activity">
	  <Version>1.9.1.1</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.AndroidX.Activity.Ktx">
	  <Version>1.9.1.1</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.AndroidX.Collection">
	  <Version>1.4.2.1</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.AndroidX.Collection.Ktx">
	  <Version>1.4.2.1</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4">
	  <Version>1.0.0.28</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.AndroidX.Lifecycle.LiveData">
	  <Version>2.8.4.1</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.Firebase.Messaging">
		<Version>124.0.0.1</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.Google.Dagger">
		<Version>2.52.0</Version>
	</PackageReference>
	<PackageReference Include="Xamarin.GooglePlayServices.Base">
		<Version>118.5.0.1</Version>
	</PackageReference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-ios'">
	<PackageReference Include="Xamarin.Firebase.iOS.CloudMessaging" Version="8.10.0.3" />
</ItemGroup>

Global usings in MauiProgram.cs

#if ANDROID
global using Firebase.Messaging;
global using AndroidX.AppCompat.Widget;
global using Android.App;
global using Android.Content;
#elif IOS
global using UIKit;
global using Firebase.CloudMessaging;
global using Foundation;
global using UserNotifications;
#endif

AppDelegate.cs

[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate, IMessagingDelegate
{
    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        if (Messaging.SharedInstance is null)
        {
            Firebase.Core.App.Configure();
        }

        if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
        {
            // For iOS 10 display notification (sent via APNS)
            /* For devices running iOS 10 and above, you must assign your delegate object 
             * to the UNUserNotificationCenter object to receive display notifications, 
             * and the Messaging object to receive data messages, before your app 
             * finishes launching. For example, in an iOS app, you must assign it 
             * in the WillFinishLaunching or FinishedLaunching method.
            */

            Messaging.SharedInstance.Delegate = this;
            Messaging.SharedInstance.AutoInitEnabled = true;

            var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
            UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
            {
                if (error is not null)
                {
                    LogError(error.LocalizedDescription);
                }
            });

            UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
        }
        else
        {
            // iOS 9 or before
            UIUserNotificationType allNotificationTypes = UIUserNotificationType.Alert;
            UIUserNotificationSettings settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
            UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
        }

        UIApplication.SharedApplication.RegisterForRemoteNotifications();

        return base.FinishedLaunching(application, launchOptions);
    }

/*
If you want to get notifications while the app is closed . Try messing with these .

    [Foundation.Export("application:didReceiveRemoteNotification:")]
    public void ReceivedRemoteNotification(UIKit.UIApplication application, Foundation.NSDictionary userInfo)
    {
    }

    [Foundation.Export("application:didReceiveRemoteNotification:fetchCompletionHandler:")]
    public async void DidReceiveRemoteNotification(UIKit.UIApplication application, Foundation.NSDictionary userInfo, Action<UIKit.UIBackgroundFetchResult> completionHandler)
    {
    }
*/

// This is FCM specific for firebase tokens
    [Export("messaging:didReceiveRegistrationToken:")]
    public void DidReceiveRegistrationToken(Messaging message, string regToken)
    {
    }
}

UserNotificationCenterDelegate.cs

    public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
    {
        // For some reason I found that calling base.DidReceiveNotificationResponse(...) and base.WillPresentNotification(...) were causing issues so I removed them. 
  

        public async override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
        {
        }
        public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
        { 
            if (AppIsInForeground != true)
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(14, 2))
                {
                    completionHandler(UNNotificationPresentationOptions.List | UNNotificationPresentationOptions.Banner | UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Sound);
                }
                else if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0)) 
                {
                    completionHandler(UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Sound);
                }
                else
                {
                    // Do our notifications need more configuration to work below 10?
                    completionHandler(UNNotificationPresentationOptions.Alert);
                }
            }
        }
    }

its-jefe avatar Sep 27 '24 15:09 its-jefe

What's is AppIsInForeground var?

mfranc28 avatar Oct 08 '24 13:10 mfranc28