Push Notifications in .NET MAUI: A Comprehensive Guide

Push Notification in .Net MAUI

Please, support my blog by clicking on our sponsors ad!


IF you need this project DM me on whatsaap "9724784544"

What are Push Notifications?

Push notifications are messages sent directly to a user's mobile device from a server, even when the app is not actively being used. They are a crucial part of mobile app development, enabling real-time communication with users. Notifications can inform users about new content, updates, reminders, or other important information, thus enhancing user engagement and retention.

Watch video to understand code:

Implementing Push Notifications in Android and iOS using .NET MAUI

In this blog, we'll explore how to implement push notifications in a .NET MAUI application for both Android and iOS platforms. We'll start by setting up a Firebase account, configuring the necessary dependencies, and writing the required code for Android and iOS. 

Setting Up a Firebase Account

  • Go to Firebase Console: Navigate to the Firebase Console.
  • Create a New Project: Click on "Add project" and follow the on-screen instructions.


    Push notification in .NET MAUI

  • Add an App to Your Project: Choose Android, and register your app with the package name.
    Push Notification in .NET MAUI

Push Notification in .NET MAUI

Push Notification in .NET MAUI

Push Notification in .NET MAUI

Download the Configuration File: Download the google-services.json file and place it in the root of your Android project.

Implementing Push Notifications in Android

Step 1: Install NuGet Packages

First, install the following NuGet packages in your .NET MAUI project:

  • Xamarin.GooglePlayServices.Base (118.1.0)
  • Xamarin.Firebase.Messaging (123.0.7)
  • Xamarin.Google.Dagger (2.41.0.2)

Ensure you install the latest versions. If you encounter any issues, use the specified versions above.

Step 2: Create Firebase Service

In the Platform -> Android folder, create a new folder named Services. Add a new class FirebaseService and write the following code

[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("DeviceToken"))
        {
            Preferences.Remove("DeviceToken");
        }
        Preferences.Set("DeviceToken", 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 | ActivityFlags.SingleTop);

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

        var pendingIntent = PendingIntent.GetActivity(this, MainActivity.NotificationID, intent, PendingIntentFlags.OneShot | PendingIntentFlags.Immutable);

        var notificationBuilder = new NotificationCompat.Builder(this, MainActivity.Channel_ID)
            .SetContentTitle(title)
            .SetSmallIcon(Resource.Mipmap.appicon)
            .SetContentText(messageBody)
            .SetChannelId(MainActivity.Channel_ID)
            .SetContentIntent(pendingIntent)
            .SetAutoCancel(true)
            .SetPriority((int)NotificationPriority.Max);

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

Explanation:

FirebaseService inherits from FirebaseMessagingService to handle Firebase Cloud Messaging (FCM) events.
OnNewToken: Called when a new token is generated. The token is stored using Xamarin.Essentials' Preferences.
OnMessageReceived: Handles incoming messages and invokes SendNotification.
SendNotification: Builds and displays the notification using NotificationCompat.Builder.

Step 3: Modify MainPage.cs
In MainPage.cs, add the following code to retrieve the device token:
private string _deviceToken;

public MainPage()
{
    InitializeComponent();
    if (Preferences.ContainsKey("DeviceToken"))
    {
        _deviceToken = Preferences.Get("DeviceToken", "");
    }
}

Step 4: Update AndroidManifest.xml
Add the following permissions to AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.codecrafter.pnmaui">
	<application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true" android:label="pnmaui"></application>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission android:name="android.permission.INTERNET" />
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
</manifest>

Step 5: Modify MainActivity.cs
In MainActivity.cs, add the following code:
public class MainActivity : MauiAppCompatActivity
{
    internal static readonly string Channel_ID = "TestChannel";
    internal static readonly int NotificationID = 101;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        if (ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.PostNotifications) == Permission.Denied)
        {
            ActivityCompat.RequestPermissions(this, new String[] { Android.Manifest.Permission.PostNotifications }, 1);
        }
        CreateNotificationChannel();
    }

    protected override void OnNewIntent(Intent intent)
    {
        base.OnNewIntent(intent);
        if (intent.Extras != null)
        {
            foreach (var key in intent.Extras.KeySet())
            {
                if (key == "NavigationID")
                {
                    string idValue = intent.Extras.GetString(key);
                    if (Preferences.ContainsKey("NavigationID"))
                        Preferences.Remove("NavigationID");

                    Preferences.Set("NavigationID", idValue);
                }
            }
        }
    }

    private void CreateNotificationChannel()
    {
        if (OperatingSystem.IsOSPlatformVersionAtLeast("android", 26))
        {
            var channel = new NotificationChannel(Channel_ID, "Test Notification Channel", NotificationImportance.Default);
            var notificationManager = (NotificationManager)GetSystemService(Android.Content.Context.NotificationService);
            notificationManager.CreateNotificationChannel(channel);
        }
    }
}

Explanation:

Channel_ID and NotificationID are used to identify the notification channel and notifications, respectively.
OnCreate: Checks for notification permissions and creates a notification channel.
OnNewIntent: Handles new intents and processes the data if the app is opened via a notification.
CreateNotificationChannel: Creates a notification channel for Android 8.0 and above.

Test Push Notification
  • Deploy your application to your iOS device.
  • Retrieve the device token generated on the first app launch.
  • Go to the Firebase Console and create a new campaign.
  • Enter the title and message, then send a test message using the device token.

Implement Push Notification in IOS

We'll go through setting up the necessary configurations on the Apple Developer portal, Firebase console, and finally implementing the code in our .NET MAUI project.

Setting Up Apple Developer Account

Step 1: Create Development Certificate

  • Log in to your Apple Developer account.
  • Navigate to Certificates, Identifiers & Profiles.
  • Create a new development certificate.
  • Download and install the certificate on your Mac by double-clicking the downloaded profile.

Step 2: Create Bundle Identifier

  • Create a unique bundle identifier for your app.

Step 3: Add Testing Device

  • In the Devices section, add the UDID of your testing device.

Step 4: Create Provisioning Profile

  • Create a development provisioning profile.
  • Download and install the profile on your Mac by double-clicking the downloaded profile.

Step 5: Create APNs Key

  • In the Keys section, create a new APNs key for push notifications.
  • Download and save this key securely, as you can only download it once.

Adding App to Firebase Console

  • Open your project in the Firebase Console.
  • Add a new iOS app by clicking on the "Add App" option and selecting iOS.
  • Register your app with the bundle identifier you created earlier.
  • Download the GoogleService-Info.plist file.

Configuring APNs in Firebase Console

  • Go to Project Settings > Cloud Messaging.
  • Under the iOS app section, upload the APNs Auth Key you created from the Apple Developer portal.
  • Add the Key ID and Team ID from the Apple Developer account.

Implementing Push Notifications in .NET MAUI (iOS)

Step 1: Create a .NET MAUI Project

  • Create a new .NET MAUI project or update an existing project's bundle identifier to match the one created in your Apple Developer account.

Step 2: Install NuGet Package

  • Install the necessary NuGet package for Firebase Cloud Messaging:
  • Xamarin.Firebase.iOS.CloudMessaging --version 8.10.0.2
Step 3: Update AppDelegate.cs
  • Add the following code to your AppDelegate.cs file in the iOS platform folder:

using Firebase.CloudMessaging;
using Firebase.Core;
using Foundation;
using UIKit;
using UserNotifications;

namespace PNMAUI;

[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
    public object completionhandler { get; private set; }

    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        Firebase.Core.App.Configure(new Options("AddGoogleAppID", "AddGcmSenderID")
        {
            ApiKey = "AddAPIKey",
            ClientId = "AddClientID",
            BundleId = "com.codecrafter.pnmaui",
            ProjectId = "YourProjectID"
        });

        if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
        {
            var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
            UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
            {
                Console.WriteLine(granted);
            });

            UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();

            Messaging.SharedInstance.AutoInitEnabled = true;
            Messaging.SharedInstance.Delegate = this;
        }
        UIApplication.SharedApplication.RegisterForRemoteNotifications();

        return base.FinishedLaunching(application, launchOptions);
    }

    [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
    public void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
    {
        // Handle notification when received
    }

    [Export("messaging:didReceiveRegistrationToken:")]
    public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
    {
        if (Preferences.ContainsKey("DeviceToken"))
        {
            Preferences.Remove("DeviceToken");
        }
        Preferences.Set("DeviceToken", fcmToken);

        App.Current.MainPage.DisplayAlert("Device Token", fcmToken, "OK");
    }
}

Explanation:

FinishedLaunching: Configures Firebase and sets up notification permissions and delegates.
DidReceiveRemoteNotification: Handles actions when a notification is received.
DidReceiveRegistrationToken: Saves the device token for push notifications.

GoogleAppID:You Will Get From Project Setting / General Tab (Firebase Console)
GcmSenderID: Obtain from the GoogleService-Info.plist file
ApiKey: Obtain from the GoogleService-Info.plist file
Client ID: Retrieve from the GoogleService-Info.plist file
BundleID: Your project's application identifier
ProjectID: Find in the Project Settings under the General tab in the Firebase Console

Step 4: Create UserNotificationCenterDelegate.cs
Create a new file named UserNotificationCenterDelegate.cs in your iOS platform folder with the following code:
using UserNotifications;

namespace PNMAUI.Platforms.iOS
{
    public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
    {
        public UserNotificationCenterDelegate()
        {
        }

        public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
        {
            base.WillPresentNotification(center, notification, completionHandler);
            completionHandler(UNNotificationPresentationOptions.Alert);
        }
    }
}

Explanation:

  • WillPresentNotification: Ensures notifications are displayed even when the app is in the foreground.
Step 5: Create Entitlements.plist
  • Create a file named Entitlements.plist in your iOS platform folder with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>aps-environment</key>
    <string>development</string>
</dict>
</plist>

Explanation:

  • aps-environment: Specifies the push notification environment (development or production).
Testing Push Notifications
  • Deploy your application to your iOS device.
  • Retrieve the device token generated on the first app launch.
  • Go to the Firebase Console and create a new campaign.
  • Enter the title and message, then send a test message using the device token.
Conclusion
In this blog, we have set up Firebase and implemented push notifications for Android using .NET MAUI. We created a service to handle FCM messages, configured the main activity to manage notification channels and intents, and ensured necessary permissions are in place.

Additionally, we extended the push notification implementation to iOS. We walked through the setup of the Apple Developer account, including creating certificates, provisioning profiles, and APNs keys. We also configured the Firebase console for iOS, added the necessary NuGet packages, and implemented the code to handle notifications in the AppDelegate.

By following these steps, you can enhance user experience and maintain a robust communication channel with your app's users. Stay tuned for more updates and enhancements in future posts!

Comments

  1. Thanks for the detail article. I am facing issue when integrating in MAUI iOS. I followed the same steps provided but unable to get GoogleClientId and AppID while initializing firebase object like below:
    Firebase.Core.App.Configure(new Options("AddGoogleAppID", "AddGcmSenderID")
    {
    ApiKey = "AddAPIKey",
    ClientId = "AddClientID",
    BundleId = "com.codecrafter.pnmaui",
    ProjectId = "YourProjectID"
    });

    Where can I find ClientID and GoogleAppID, kindly suggest.

    ReplyDelete
  2. Why all the xamarin.x nuget packages, are there not better Maui alternatives isntead?

    ReplyDelete
  3. im receiving the notification but how to handle when the user tapped the notification to display the data from the message?

    ReplyDelete
  4. Thanks, i got more clear idea

    ReplyDelete
  5. Hello, can you help me why my App build fails?

    ReplyDelete
  6. Error when installing package as you mentioned with same version for IOS

    System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Users\Admin\.nuget\packages\xamarin.firebase.ios.installations\8.10.0.1\lib\net6.0-ios15.4\Firebase.Installations.resources\FirebaseInstallations.xcframework\ios-arm64_i386_x86_64-simulator\FirebaseInstallations.framework\Headers\FirebaseInstallations-umbrella.h'.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

    ReplyDelete
    Replies
    1. That happens because some nuget paths are too long(plus that 260 characters). I solved by mapping "C:\Users\Admin\.nuget\packages\" to "E:\" using command line subst. Also in Windows you must add a system variable called NUGET_PACKAGES and set it to "E:\" to tell nuget to use this path intead for the packages cache. I also had map the project compilation output folder(usually \bin) to shorten it.

      Delete
  7. I Can't find the ClientId in GoogleService-info.plist. Any help?

    ReplyDelete

Post a Comment

Popular posts from this blog

Explore the UI libraries available for .NET MAUI at no cost.

Push Notification using Firebase in xamarin form (Android and IOS)

School UI Design using xamarin form