.NET MAUI on push notification click error is thrown: 'Window was already created'

208 Views Asked by At

I added a push notification to my app, and I receive the notification only the app is running. When I click on the notification, the application detects it and when I got to the point where I want to navigate to specific page, I got on error: System.InvalidOperationException: 'Window was already created'

My FireService:

using Android.App;
using Android.Content;
using AndroidX.Core.App;
using Firebase.Messaging;

[Service(Exported = true)]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
    public FirebaseService()
    {
    }

    public override void OnNewToken(string token)
    {
        base.OnNewToken(token);

        if (Preferences.ContainsKey(StorageKeys.Public.GCM))
        {
            Preferences.Remove(StorageKeys.Public.GCM);
        }

        Preferences.Set(StorageKeys.Public.GCM, token);
    }

    public override void OnMessageReceived(RemoteMessage message)
    {
        base.OnMessageReceived(message);

        var notification = message.GetNotification();
        SendNotification(notification.Body, notification.Title, message.Data);
    }

    private void SendNotification(string messageBody, string title, IDictionary<string, string> data)
    {
        var intent = new Intent(this, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.ClearTop);

        foreach (var key in data.Keys)
        {
            var value = data[key];
            intent.PutExtra(key, value);
        }

        var pendingIntent = PendingIntent.GetActivity(this, MainActivity.NotificationId, intent, PendingIntentFlags.OneShot);

        var notificationBuilder = new NotificationCompat.Builder(this, MainActivity.ChannelId)
            .SetContentTitle(title)
            .SetSmallIcon(Resource.Drawable.ic_notification)
            .SetContentText(messageBody)
            .SetChannelId(MainActivity.ChannelId)
            .SetContentIntent(pendingIntent)
            .SetPriority(2);

        var notificationManager = NotificationManagerCompat.From(this);
        notificationManager.Notify(MainActivity.NotificationId, notificationBuilder.Build());
    }

Android MainActivity:

[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
    internal static readonly string ChannelId = "MyChanel";
    internal static readonly int NotificationId = 123456789;

    public override void OnBackPressed() { }

    protected override void OnCreate(Bundle? savedInstanceState)
    {
       base.OnCreate(savedInstanceState);

        if (Intent?.Extras != null)
        {
            foreach (var key in Intent?.Extras.KeySet() ?? [])
            {
                if (key == "NavigateTo")
                {
                    var page = Intent?.Extras.GetString(key);

                    if (Preferences.ContainsKey("NavigateTo"))
                    {
                        Preferences.Remove("NavigateTo");
                    }

                    if (!string.IsNullOrEmpty(page))
                    {
                        HandleNotification(page);
                    }
                }
            }
        }
        else
        {
            CreateNotificationChanel();
        }
    }

    private void CreateNotificationChanel()
    {
        if (!OperatingSystem.IsOSPlatformVersionAtLeast("android", 26))
        {
            return;
        }

        var channel = new NotificationChannel(ChannelId, "BSI Notification Chanel", NotificationImportance.Default);
        
        var manager = (NotificationManager)GetSystemService(NotificationService);
        manager.CreateNotificationChannel(channel);
    }

    private void HandleNotification(string navigateToPage)
    {
        WeakReferenceMessenger.Default.Send(new PushNotificationReceivedMessage
        {
            PageToNavigate = navigateToPage
        });
    }
}

Then the App receives the message where I try to navigate to the page that is in the push notification data.

public partial class App : Application
{
    public App(SecurityService securityService, UserService userService)
    {
        InitializeComponent();
        SubScribeOnNotificationNavigation();

        MainPage = new NavigationPage(new SplashPage());
    }


    private void SubScribeOnNotificationNavigation()
    {
        WeakReferenceMessenger.Default.Register<PushNotificationReceivedMessage>(this, async (recepient, messaage) =>
        {
            await AppShell.Current.GoToAsync(messaage.PageToNavigate);
        });
    }
}

The code passes and returns to MainActivity and the throws an error. I tried some different scenarios, but all failed with the same error.

My other concern is that the message is only received while the app is running.

thnx

EDIT

I added to the manifest.xml the default notification id meta data.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" package="hu.bsi.info" android:versionName="1.0">&gt;
    <application android:usesCleartextTraffic="true" 
                 android:allowBackup="true" 
                 android:icon="@mipmap/appicon"
                 android:supportsRtl="true"
                 android:networkSecurityConfig="@xml/network_security_config"
                 android:label="BlackStageInfo">
        <meta-data android:name="com.google.firebase.messaging.default_notification_icon"
                   android:resource="@drawable/ic_notification" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/default_notification_channel_id" />
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <uses-feature android:name="android.hardware.location" android:required="false"/>
    <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
    <uses-feature android:name="android.hardware.location.network" android:required="false"/>
    <queries>
        <intent>
            <action android:name="android.media.action.VIDEO_CAPTURE"/>
        </intent>
        <intent>
            <action android:name="android.media.action.IMAGE_CAPTURE"/>
        </intent>
        <intent>
            <action android:name="android.intent.action.DIAL"/>
            <data android:scheme="tel"/>
        </intent>
    </queries>
    <uses-sdk android:targetSdkVersion="34" android:minSdkVersion="24"/>
</manifest>

I am getting an error: Severity Code Description Project File Line Suppression State Error APT2260 resource string/default_notification_channel_id (aka hu.bsi.info:string/default_notification_channel_id) not found. This error is likely caused by an issue with the AndroidManifest.xml file or an Android manifest generation attribute in a source code file.

0

There are 0 best solutions below