dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.92k stars 526 forks source link

`TrimMode=full` seems to break android push notifications on MAUI .net 9 preview 3 #8940

Closed jkommeren closed 1 month ago

jkommeren commented 3 months ago

Android application type

.NET Android (net7.0-android, net8.0-android, etc.)

Affected platform version

VS 2022 17.10.0 preview 7

Description

Notifications don't arrive in some cases when "PublishTrimmed" is set to true and building it in Release mode (which is the default)

Point is: @jonathanpeppers suggested to create a new issue here if the issue still persisted on .net 9 preview 3. As far as I'm aware it has been an issue at least since .net 7, but also very likely .net 6.

Originally posted by @jonathanpeppers in https://github.com/xamarin/xamarin-android/issues/5652#issuecomment-2010266232 Also mentioned in https://github.com/dotnet/maui/issues/16014 And at least some people seem to be affected here https://github.com/dotnet/maui/discussions/19900

Steps to Reproduce

  1. Create project in .net 9 preview 3
  2. Add firebase push notification support via Xamarin.Firebase.Messaging" Version="123.3.1.1", google-services.json, etc.
  3. Create a channel with priority max or high, ask for permission to send notifications
  4. Build project in release mode, setting PublishTrimmed to true (and AOT on or off, no difference)
  5. Deploy it to Android device
  6. Launch application
  7. Send notification via Firebase Console with application open, specifying the channel
  8. Notification does not arrive

Did you find any workaround?

Set PublishTrimmed to False or deploying in debug mode fixes the issue immediately: Then the notification does arrive.

Also one odd thing: When the application is in the background, sending a notification via the Firebase console does pop up. (But if it's sent as a Data message instead, the FirebaseMessagingService does not pick it up in foreground nor background. That is also fixed by using non-trimming or debug)

Maybe there's something I completely don't understand about Android notifications in MAUI, but the way I understand it, Debug should behave like Release mode in these cases right? And Non-trimmed vs Trimmed in Release mode too?

Relevant log output

There is no log output. No unhandled exceptions. Nothing appears to happen when the notification is supposed to arrive.
jkommeren commented 3 months ago

Also, there is plenty of evidence people seem to be accepting "turning off trimming" as a "solution". But that's not how it should be right?

At the very least it's not clear to the average user (like me) what needs to be done in this case :) please help me solve the issue that has been wrecking my brain for months.

https://stackoverflow.com/questions/76045900/net-maui-why-would-push-notifications-not-work-the-same-after-publishing

https://github.com/xamarin/xamarin-android/issues/5652

jonathanpeppers commented 3 months ago

@jkommeren can you share a sample app that shows this issue?

If some code in your app is supposed to be running (and isn't), is the code trimmed away? We could inspect a Release .apk file and see what the difference between PublishTrimmed=true and false is.

Generally, you can preserve a single method as a workaround instead of disabling trimming completely. But you, of course, would need to know which method.

jkommeren commented 3 months ago

@jkommeren can you share a sample app that shows this issue?

If some code in your app is supposed to be running (and isn't), is the code trimmed away? We could inspect a Release .apk file and see what the difference between PublishTrimmed=true and false is.

Generally, you can preserve a single method as a workaround instead of disabling trimming completely. But you, of course, would need to know which method.

Thank you for your swift reply. How can I inspect the APK? 😊 I think indeed that's where the problem lies.

jonathanpeppers commented 3 months ago

If you run this tool on an .apk, it can unpack .dll files:

Then you can just open them in ILSpy or your favorite decompiler.

tranb3r commented 3 months ago

The problem here is that the trimmer is getting rid of an android service in the Plugin.Firebase library, responsible for receiving the notification. I've already discussed this topic with @jonathanpeppers on discord. My understanding is that the trimmer cannot "know" that an android service is used by your app. Maybe this could be fixed... who knows. But the easiest fix (or workaround) is to make sure your app is preserving this service. You can skip trimming for the whole assembly, or add a DynamicDependency attribute in your code path. A better fix would be to add an Initialize method in the lib, and add the DynamicDependency attribute in this method. More details here: https://github.com/TobiasBuchholz/Plugin.Firebase/issues/144#issuecomment-1716038986

tranb3r commented 3 months ago

Also, about inspecting the apk, I've found that the easiest way to do it is to look into YourApp\obj\Release\net8.0-android34.0\android-arm64\linked folder. In this folder, you'll find all trimmed assemblies after your build, and you can easily open any dll in dnspy. In Plugin.Firebase.CloudMessaging.dll, look for Plugin.Firebase.CloudMessaging.Platforms.Android.MyFirebaseMessagingService. If it's missing, then the trimmer has been too aggressive, and your notifications won't work.

jonathanpeppers commented 3 months ago

@jkommeren so are you using TrimMode=full or default settings?

Services should not be trimmed away by default -- it should be using TrimMode=partial by default, which was the same as "SDK only" in the Xamarin days.

tranb3r commented 3 months ago

Yes this is with full trimming.

jkommeren commented 3 months ago

@jonathanpeppers yes indeed with full trimming. I think I'm making progress. With the suggestions from tranb3r I have managed to get it working with .net 8 and his library Plugin.Firebase. But then I removed his suggestions, and it was still working (but I'm guessing that's because I didn't do a full clean of obj and bin folders, just from VS)

I'm still a bit puzzled why my own implementation of the FirebaseMessagingService (SuperFirebaseMessagingService.OnMessageReceived) is not being fired though, even though it's present in the DLL (looking at DnSpy), in the linked folder like suggested, and it's working in Debug mode.

I think there's something I'm missing.

I can create a sample project this weekend to upload and have a proper go at .net 9 preview 3. Trimming is definitely different there, it's much slower too :D

Thanks for your help so far.

jonathanpeppers commented 3 months ago

I wouldn't expect TrimMode=full to work well in .NET 8, as we didn't solve all the trimmer warnings until .NET 9 Preview 3.

But it still seems like there might be some things that we should go test in .NET 9 w/ TrimMode=full:

I wonder if some of these are trimmed away and shouldn't be.