thomasgalliker / Plugin.FirebasePushNotifications

Receive and handle firebase push notifications in .NET MAUI apps
MIT License
51 stars 5 forks source link

Problems receiving notifications on Android #41

Closed Mano176 closed 3 weeks ago

Mano176 commented 1 month ago

Hello, I am trying to receive notifications on Android but I am facing two problems which I am unable to solve by looking at the examples in the sample project and in the readme and the other issues.

Problem 1

Foreground notifications (notifications the app receives while the it is running) only call OnNotificationReceived but don't show the notification in the status bar. I tried to trigger a local notification in OnNotificationReceived but I have the feeling that this is not the intended way.

Problem 2

Background notifications (notifications the app receives while it is not running) are displayed in the status bar like the first image in your readme and clicking on them opens the app. I also see that in OnCreate the Intent.Extras bundle is not empty, but it does not contain my notification data (title, body and additional data). The bundle just contains the follwing data:

google.delivered_priority: high google.sent_time: google.ttl: google.original_priority: high google.product_id: from: 151007389476 google.message_id: [some id] gcm.n.analytics_data: collapse_key: [my package name]

My code in MainActivity.cs

protected override void OnCreate(Bundle savedInstanceState)
{
    Instance = this;
    // gets called when the app is started
    // if it is started via click on background notification Intent.Extras is not empty
    Dictionary<string, object> notification = [];
    string notificationString = "";
    if (Intent?.Extras is Bundle extras && extras.KeySet() is ICollection<string> keys)
    {
        foreach (string key in keys)
        {
            string value = extras.GetString(key, defaultValue: null);
            notification.Add(key, value);
            notificationString += key + ": " + value + System.Environment.NewLine;
        }
    }
    Tools.AppendPushLog("oncreate1: " + notificationString);
    base.OnCreate(savedInstanceState);
    Initialize();
}
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
    Instance = this;
    // app seems to never start via this function
    Tools.AppendPushLog("oncreate2: " + Intent?.Extras);
    base.OnCreate(savedInstanceState, persistentState);
    Initialize();
}
private async void Initialize()
{
    CreateNotificationChannel(); // probably not needed, if we make it work that the Firebase notification is displayed while the app is open

    PermissionStatus status = await MainThread.InvokeOnMainThreadAsync(Permissions.RequestAsync<Permissions.PostNotifications>);

    string pushLog = Tools.ReadPushLog();
    System.Diagnostics.Debug.WriteLine(pushLog);
    if (status == PermissionStatus.Granted)
    {
        System.Diagnostics.Debug.WriteLine("token: " + await CrossFirebasePushNotification.Current.GetTokenAsync());
        CrossFirebasePushNotification.Current.OnTokenRefresh += (sender, eventArgs) =>
        {
            Console.WriteLine("new token: " + eventArgs.Token);
        };

        CrossFirebasePushNotification.Current.OnNotificationOpened += (sender, eventArgs) =>
        {
            // never called yet
            Tools.AppendPushLog("notification opened: " + eventArgs);
            System.Diagnostics.Debug.WriteLine("Notification opened: " + eventArgs);
        };

        CrossFirebasePushNotification.Current.OnNotificationAction += (sender, eventArgs) =>
        {
            // never called yet (but probably not wanted, because we wan't to do an action when the notification itself is clicked and we don't want to display buttons in the notification)
            Tools.AppendPushLog("notification action: " + eventArgs);
            System.Diagnostics.Debug.WriteLine("Notification action: " + eventArgs);
        };

        CrossFirebasePushNotification.Current.OnNotificationError += (sender, eventArgs) =>
        {
            Tools.AppendPushLog("notification error: " + eventArgs);
            System.Diagnostics.Debug.WriteLine("Notification error: " + eventArgs);
        };

        CrossFirebasePushNotification.Current.OnNotificationReceived += (s, p) =>
        {
            Tools.AppendPushLog("notification receieved: " + p);
            System.Diagnostics.Debug.WriteLine("Notification opened: " + p);

            // This part after here is probably not really needed, because we would rather just show the notification from firebase
            // if the comment above is not possible, we need to figure out how to make this notification clickable, so that we can show custom pages on click
            string title = "", message = "";
            if (p.Data.TryGetValue("title", out object titleObject))
            {
                title = titleObject.ToString();
            }
            if (p.Data.TryGetValue("body", out object messageObject))
            {
                message = messageObject.ToString();
            }

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "LMDefaultNotificationChannel")
            .SetContentTitle(title)
            .SetContentText("I am the notification created via the NotificationCompat.Builder")
            .SetSmallIcon(_Microsoft.Android.Resource.Designer.ResourceConstant.Drawable.clock);

            Notification notification = builder.Build();
            NotificationManager notificationManager = GetSystemService(NotificationService) as NotificationManager;
            using NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.From(this);
            notificationManagerCompat.Notify(0, notification);
        };

        CrossFirebasePushNotification.Current.RegisterForPushNotifications();
    }
}
private void CreateNotificationChannel()
{
    if (OperatingSystem.IsAndroidVersionAtLeast(26))
    {
        NotificationChannel channel = new NotificationChannel("LMDefaultNotificationChannel", "My Notification Channel", NotificationImportance.Max);
        using NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.From(this);
        notificationManagerCompat.CreateNotificationChannel(channel);
    }
}

I am creating the notifications via https://console.firebase.google.com/project/[myproject]/notification/compose

I have the feeling that I am just missing some fundamental part in the setup, but am lost to what exactly is wrong. I hope you can help me out here.

Mano176 commented 1 month ago

I now managed to send notifications via an own .net project:

Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "[path to]\\firebase-adminsdk.json");
FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
});

string registrationToken = "my device token";

// See documentation on defining a message payload.
Message message = new Message()
{
    Token = registrationToken,
    //Data = new Dictionary<string, string>()
    //{
    //    { "title", "Weather Update" },
    //    { "body", "Pleasant with clouds and sun" },
    //},
    Notification = new Notification()
    {
        Title = "Title",
        Body = "I am a message sent via the .NET Project",
    },
    Android = new AndroidConfig()
    {
        Priority = Priority.High,
    },
};

string response = FirebaseMessaging.DefaultInstance.SendAsync(message).GetAwaiter().GetResult();
Console.WriteLine("Successfully sent message: " + response);

I'm not quite sure wether I should use the Notification or Data parameter there. But with both approaches I get the same results as described above.

I am also confused wether we should include any receiver tags in the AndroidManifest.xml like this guy did: #17 So far doing this does not seem to change anything for me.

I should maybe also mention, that receiving background notifications only seems to work really unreliable and there's a huge delay between sending and receiving them (foreground notifications are received instantly).

Update

I updated the nuget reference from 1.0.26 to 2.2.69-pre and now everything seems to work fine. Had to do some migrations. Most of them were renaming events, one bigger migration was adding this to CreateMauiApp:

.UseFirebasePushNotifications(options: (FirebasePushNotificationOptions options) =>
{
    options.Android.NotificationChannels =
    [
        new NotificationChannelRequest()
        {
            ChannelId = "LMDefaultNotificationChannel",
            ChannelName = "My Channel Name",
            Description = "Channel Description",
            Importance = Android.App.NotificationImportance.Max,
            IsDefault = true
        }
    ];
})

The stuff in OnNotificationReceived is no longer needed and NotificationOpened is not called properly when I click the notifications. Also my OnCreate method now properly receives the notification data.

One small thing I noticed (that might help others) is, that when I debug the app with Visual Studio and then close the app, I have to open the app once again (but this time from the device and not with Visual Studio) and close it again to be able to receive background notifications.

thomasgalliker commented 1 month ago

First of all, I‘m sorry that version 1.x is still the latest stable version. 1.x was the direct migration from the previous xamarin plugin for FCM.

To the other points, I‘ll come back to you as soon as I can. The steps you went trough and the comments noted help me to understand where I have to extend to documentation. (I know, it barely doesnt exist…).

thomasgalliker commented 3 weeks ago

@Mano176 you can try the latest version of the plugin. It‘s now more stable and tested with a lot of different push notification messages.

If there is still anything unclear or buggy, I kindly ask you to open a new issue - or we reopen this one 👍🏻