Plugin.FirebasePushNotifications icon indicating copy to clipboard operation
Plugin.FirebasePushNotifications copied to clipboard

[Question] Android Not Receiving IFirebasePushNotification.NotificationReceived Event

Open jamesbdarcy opened this issue 7 months ago • 30 comments

Thomas

Your plugin is wonderful. Thank you.

I have been able to successfully integrate the plugin and have it working for both Android and iOS. I am receiving Push notifications from FCM on both OS's whether the app is stopped, in background or forground. Fabulous!

There is one anomoly, however.

I have placed event handlers for the IFirebasePushNotification events within the App.xaml.cs file, rather than a Page, as I would like to be notified at all times when an event comes in and not rely on the user being on a page. I have placed the event handlers in App.xaml.cs, rather than Platform/Android/MainActivity as I would like to be notified of the TokenRefreshed, NotificationAction and NotificationReceived events on both OS's.

Placing them in App.xaml.cs works fine for iOS but not in Android.

In Android I do receive the NotificationAction when the user selcts an action but I do not receive either of the other two events, NotificationReceived and TokenRefreshed.

Is there a reason that these events are not being raised on the Android platform? Note, that I am receiving the actual Push Notifications, but the library events are not being raised.

I hope you can assist.

Kind regards

James

jamesbdarcy avatar May 19 '25 13:05 jamesbdarcy

I should add that I am using dotnet 9. Not sure if that makes any difference.

jamesbdarcy avatar May 19 '25 14:05 jamesbdarcy

Hi James. We're talking about different problems here. First of all, it's all it's totally fine to subscribe the events in App.xaml.cs. For better testability however, I would recommend to subscribe them in a viewmodel - kind of "the main viewmodel" which is always present while the app is in use. No matter which sub-page the user navigated to, you'll still received the event notifications as long as the root/main page is on the navigation stack.

It's hard to tell why NotificationReceived and TokenRefreshed events are not fired in your case. Of course, they should be raised at some point. I would not care too much about TokenRefreshed as it takes pretty much time until a token is invalidated. Just add logging and you'll sooner or later see log messages in your log.

Generally, it pays off to setup logging. I do write a lot of useful log messages to the log which helps debugging problems.

Would you mind to create a small reproduction app so that I can see what you're trying to achieve? Did you also checkout the sample app in this repo? And, there is a quite big postman collection with a lot of sample push notifications for several different scenarios. Have a look.

thomasgalliker avatar May 19 '25 14:05 thomasgalliker

Hi Thomas

Thanks for your response.

You know what, I never thought through the fact that the MainView is always on the stack! I feel kinda stupid about that. It's probably easiest if I put the event handlers in there and see what happens.

I have looked fairly closely at the sample app and that helped me understand the mechanisms of your library very well. I also use logging quite a lot.

I will have a look at th ePostman app as well.

Cheers

James

jamesbdarcy avatar May 19 '25 21:05 jamesbdarcy

Don't worry. Feel free to share a small repro app so I can assist you in resolving the issue. Sometimes it just needs some time to get the stuff working. It's a pretty complex topic to be honest :)

thomasgalliker avatar May 20 '25 09:05 thomasgalliker

I am not receiving NotificationReceived event when the notification is shown and the app is running (i.e. notification with high importance). I this intended behavior?

Bludator avatar May 26 '25 11:05 Bludator

This is not intended behavior.

thomasgalliker avatar May 26 '25 12:05 thomasgalliker

It can have a number of reasons why NotificationReceived event is not fired. It's really hard to support the troubleshooting process if I have no additional context. I'd recommend you use the latest pre-release 3.2.8-pre which adds some fail safety in certain scenarios. Also, make sure your app uses Microsoft.Extensions.Logging as we write a lot of useful messages to ILogger. One last hint: Try to get the sample app in this repo to work with your own GoogleService-Info.plist (iOS) resp. google-services.json (Android).

thomasgalliker avatar May 26 '25 14:05 thomasgalliker

You are to quick for me 😅. I have created issue for it now

Bludator avatar May 27 '25 12:05 Bludator

Cool, let's discuss it there #127

thomasgalliker avatar May 27 '25 14:05 thomasgalliker

Could this issue be related with #132?

thomasgalliker avatar Jun 07 '25 15:06 thomasgalliker

There is a brand new pre-release 4.0.1-pre available which targets to solve this issue. Can you give it a try?

thomasgalliker avatar Jun 12 '25 14:06 thomasgalliker

THanks Thomas

I'll try that over the weekend. I appreciate your response.

Regards

James

jamesbdarcy avatar Jun 13 '25 11:06 jamesbdarcy

Thomas

I don't have dotnet 6.0 installed - I only have 9.0. Attempting to add the package I get the following error message.

System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Users\James\.nuget\packages\adame.firebase.ios.core\11.10.0\lib\net6.0-ios16.1\Firebase.Core.resources\FirebaseCoreInternal.xcframework\ios-arm64_x86_64-simulator\FirebaseCoreInternal.framework\Modules\FirebaseCoreInternal.swiftmodule\arm64-apple-ios-simulator.abi.json'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
   at System.IO.File.Create(String path)
   at NuGet.Packaging.StreamExtensions.Testable.MmapCopy(Stream inputStream, String fileFullPath, Int64 size)
   at NuGet.Packaging.StreamExtensions.Testable.CopyToFile(Stream inputStream, String fileFullPath)
   at NuGet.Packaging.PackageFileExtractor.ExtractPackageFile(String source, String target, Stream stream)
   at NuGet.Packaging.PackageArchiveReader.CopyFiles(String destination, IEnumerable`1 packageFiles, ExtractPackageFileDelegate extractFile, ILogger logger, CancellationToken token)
   at NuGet.Packaging.PackageReaderBase.CopyFilesAsync(String destination, IEnumerable`1 packageFiles, ExtractPackageFileDelegate extractFile, ILogger logger, CancellationToken cancellationToken)
   at NuGet.Packaging.PackageExtractor.<>c__DisplayClass5_0.<<InstallFromSourceAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Common.ConcurrencyUtilities.<ExecuteWithFileLockedAsync>d__11`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NuGet.Common.ConcurrencyUtilities.<ExecuteWithFileLockedAsync>d__11`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Packaging.PackageExtractor.<InstallFromSourceAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Commands.ProjectRestoreCommand.<InstallPackageAsync>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NuGet.Commands.ProjectRestoreCommand.<>c__DisplayClass15_1.<<InstallPackagesAsync>b__4>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at NuGet.Commands.ProjectRestoreCommand.<InstallPackagesAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NuGet.Commands.DependencyGraphResolver.<ResolveAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Commands.RestoreCommand.<ExecuteRestoreAsync>d__120.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Commands.RestoreCommand.<GenerateRestoreGraphsAsync>d__100.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Commands.RestoreCommand.<ExecuteAsync>d__95.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Commands.RestoreRunner.<ExecuteAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.Commands.RestoreRunner.<CompleteTaskAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NuGet.Commands.RestoreRunner.<RunWithoutCommit>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.PackageManagement.DependencyGraphRestoreUtility.<PreviewRestoreProjectsAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.PackageManagement.NuGetPackageManager.<PreviewBuildIntegratedProjectsActionsAsync>d__89.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.PackageManagement.NuGetPackageManager.<PreviewProjectsInstallPackageAsync>d__75.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.PackageManagement.VisualStudio.NuGetProjectManagerService.<>c__DisplayClass22_0.<<GetInstallActionsAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NuGet.PackageManagement.VisualStudio.NuGetProjectManagerService.<CatchAndRethrowExceptionAsync>d__33`1.MoveNext()
Time Elapsed: 00:00:08.0669183

jamesbdarcy avatar Jun 13 '25 11:06 jamesbdarcy

@jamesbdarcy this is a well-known problem. I guess you use Windows 11 and Visual Studio 2022.

thomasgalliker avatar Jun 13 '25 12:06 thomasgalliker

Hi, i just tested the pre-release 4.0.20-pre and the NotificationReceived is now firing in android, but the system popup is not shown when app is in foreground and channel importance is set to high. It was working on the 3.2.11 version tho. Is this only occuring in my project or still an issue? Thanks in advance!

mr-dst avatar Jun 17 '25 06:06 mr-dst

Hi, i just tested the pre-release 4.0.20-pre and the NotificationReceived is now firing in android, but the system popup is not shown when app is in foreground and channel importance is set to high. It was working on the 3.2.11 version tho. Is this only occuring in my project or still an issue? Thanks in advance!

I think this is intended. You should create the notification yourself in the Received event handler by call to firebasePushNotification.NotificationBuilder.OnNotificationReceived(data). This way there is no magic to when the notification will show/not show. Note this is Android only API. I am not sure what are the defaults on iOS.

@thomasgalliker correct me if I am wrong 😅

Bludator avatar Jun 17 '25 09:06 Bludator

@mr-dst having a notification channel with Importance=High is not enough to get the system notification popup while the app runs in foreground on Android.

  • You need to send notification messages with { data: { priority: high }}
  • AND the app must have a notification channel with Importance=High.
{
    "message": {
        "token": "{{fcm_token}}",
        "notification": {
            "title": "Hello",
            "body": "https://buymeacoffee.com/thomasgalliker"
        },
        "data": {
            "priority": "high"
        }
    }
}

There was some refactoring going on between 3.2.11 and 4.0.x in this area. I believe the current notification handling in version 4.0.x is now as consistent as possible between Android and iOS. While some level of platform divergence is inevitable, we strive to keep it to a minimum without compromising on platform-specific functionality.

thomasgalliker avatar Jun 17 '25 11:06 thomasgalliker

@thomasgalliker i have the channel set to high and also the message has priority high in data. I think otherwise it wouldnt have worked in 3.2.11 right? Still in the 4.0.20-pre its not working - even when I add firebasePushNotification.NotificationBuilder.OnNotificationReceived(data) to the event like @Bludator thankfully mentioned. Funny now i reverted back to 3.2.11 and now its also not working there in foreground haha.

Do I still miss something?

Still overall I thank you very much for your precious time in this project - you did/do a great job here!

mr-dst avatar Jun 17 '25 11:06 mr-dst

Do you have a reduced-to-the-bare-minimum repro sample app which you can share? If you checkout the sample app in this repository and add your own GoogleService-Info.plist and google-services.json files you can use the postman collection in this repo to send some messages. I have no idea what the current state of your code is that doesn't work. But I have a good feeling that the sample app together with the postman calls works pretty well.

thomasgalliker avatar Jun 17 '25 11:06 thomasgalliker

Oh thanks that wont be necessary - I dont want to wast your precious time. As long as there is no bug in the project and in your tests it did work with android in foreground with version 4.0.x then I will search for the issue myself in my code and will share it then here for others.

mr-dst avatar Jun 17 '25 11:06 mr-dst

Ok, good approach. Otherwise, if you're stuck: Ask again. Just as a hint: Close the solution, remove all bin/obj folders, start again, rebuild. Helps sometimes.

thomasgalliker avatar Jun 17 '25 11:06 thomasgalliker

Update: firebasePushNotification.NotificationBuilder.OnNotificationReceived(data) is mandatory in NotificationReceived for displaying notficaiton in foreground. Also removing the bin/obj folder and rebuilding helped solve the issue.

mr-dst avatar Jun 17 '25 13:06 mr-dst

I just want to make clear that such a call is officially not required to have the library working as expected. You understand that it would be very bad design if the library needs to call itself in order to work properly. I'd like to understand what you're doing and how the library could support this scenario:

  • Android app in foreground
  • Default (or target) notification channel has Importance=High
  • Notification message has priority: high

Can you check that the notification channel had Importance=High at the time of the first startup? If it had Importance=Default, you cannot programmatically change it afterwards. Uninstall the app and reinstall it to make sure you have a notification channel with high priority.

thomasgalliker avatar Jun 17 '25 13:06 thomasgalliker

Ok first of all i want to point out that it worked fine in version 3.2.11 - just like in your official demo project - only problem there was that the NotificationReceived was not firing when the app is in foreground - but system notification was beeing shown. In version 4.0.20-pre (after bin/obj clean) the NotificationReceived works as intended in foreground but no system notification is shown unless you call FirebasePushNotification.NotificationBuilder.OnNotificationReceived(data) in the NotificationReceived

My notificationchannel has importance high on startup (first creation) - also after reinstalling its the same - i knew that already from the xamarin time back in the days.

mr-dst avatar Jun 17 '25 13:06 mr-dst

What did you configure in .UseFirebasePushNotifications(o => ... ?

thomasgalliker avatar Jun 17 '25 13:06 thomasgalliker

What did you configure in .UseFirebasePushNotifications(o => ... ?

.UseFirebasePushNotifications(options => { #if ANDROID NotificationChannelRequest defaultChannel = new NotificationChannelRequest() { ChannelId = "default", ChannelName = "Default", IsDefault = true, Importance = NotificationImportance.Max, SoundUri = global::Android.Net.Uri.Parse(pathtonotificationsound) }; options.Android.NotificationChannels = new[] { defaultChannel }; options.Android.DefaultNotificationImportance = NotificationImportance.Max; options.Android.SoundUri = global::Android.Net.Uri.Parse(pathtonotificationsound); #elif IOS // Configure iOS notifications for foreground display options.iOS.PresentationOptions = UNNotificationPresentationOptions.Alert | UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Badge; #endif })

mr-dst avatar Jun 17 '25 13:06 mr-dst

OK, I tested your configuration and it works. Did you call INotificationPermissions.RequestPermissionAsync()? If you don't have notification permissions granted, you will only receive the NotificationReceived event but no system notification popup when the android app runs in foreground.

thomasgalliker avatar Jun 18 '25 06:06 thomasgalliker

Yes I am calling the await INotificationPermissions.Current.RequestPermissionAsync();on OnStart of the App. If i keep the OnNotificationReceived commented out in the NotificationReceived i dont get notifications in foreground in version 4.0.20-pre. In version 3.2.11 works fine

mr-dst avatar Jun 18 '25 14:06 mr-dst

Just another attempt: Can you try version 4.0.1-pre?

thomasgalliker avatar Jun 18 '25 18:06 thomasgalliker

Just another attempt: Can you try version 4.0.1-pre?

4.0.1 works fine for us

sovdchains avatar Aug 01 '25 13:08 sovdchains