Push Notifications in .NET MAUI: A Comprehensive Guide
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.
- Add an App to Your Project: Choose Android, and register your app with the package name.
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());
}
}
private string _deviceToken;
public MainPage()
{
InitializeComponent();
if (Preferences.ContainsKey("DeviceToken"))
{
_deviceToken = Preferences.Get("DeviceToken", "");
}
}
<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>
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);
}
}
}
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:
- 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");
}
}
GoogleAppID:You Will Get From Project Setting / General Tab (Firebase Console)
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);
}
}
}
- WillPresentNotification: Ensures notifications are displayed even when the app is in the foreground.
- 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>
- aps-environment: Specifies the push notification environment (development or production).
- 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.
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:
ReplyDeleteFirebase.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.
I update blog. please check.
DeleteWhy all the xamarin.x nuget packages, are there not better Maui alternatives isntead?
ReplyDeleteim receiving the notification but how to handle when the user tapped the notification to display the data from the message?
ReplyDeleteAre you receiving the push notification in iOS. If yes, can you please share me the code snippets to my WA 8248966848. I am struggling for one week.
DeleteThanks, i got more clear idea
ReplyDeleteHello, can you help me why my App build fails?
ReplyDeleteThis comment has been removed by the author.
DeleteVery helpful
ReplyDeleteError when installing package as you mentioned with same version for IOS
ReplyDeleteSystem.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)
you are using .net 7??
DeleteThat 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.
DeleteI Can't find the ClientId in GoogleService-info.plist. Any help?
ReplyDeletefor all those who had this problem
Deleteif you downloaded GoogleServices-Info.plist file and it doesn't contain CLIENT_ID and REVERSE_CLIENT_ID
Solution:
Just Go to Authentication section in firebase -> Sign-in method -> Add new provider then select Google and enable it .
now download the updated GoogleService-Info.plist file now it had the CLIENT_ID and REVERSE_CLIENT_ID then replace the old one with updated one.
Thanks
How to retrieve token? I don't have mainpage.cs so I put the
ReplyDeleteif (Preferences.ContainsKey("DeviceToken"))
{
_deviceToken = Preferences.Get("DeviceToken", "");
}
On my first page and in app.xaml.cs but won't enter in the if
you have missed some steps. please follow step properly, you will get token
Deletegoogle-services.json --> Wich property I have to set? MauiAsset, Resource,.....?
DeleteAnd I check double, I follow every single step in your guide but this line: if (Preferences.ContainsKey("DeviceToken")) Is always false.
DeleteI probably misunderstood what do you mean by: Retrieve the device token generated on the first app launch.
I put a break on the previous line but I don't understand if isn't set the DeviceToken, how is possible that the Get return a token?
Hi! First, thanks for your code! I'm writting a MAUI app and folowed all steps (double check them). I don't understand when I should get the Token you mention ( "Retrieve the device token generated on the first app launch."). I put a breakpoint in line: "Preferences.Set("DeviceToken", token);" on OnNewToken, but it never hits. Please help me! Tanks once more!
ReplyDeleteHello Xamarin UI Design team, first, thank you for your tutorial, it's helping me so much..
ReplyDeleteI've followed all of your tutorial and it worked nice as expected, but then I'm facing new problem, each time I get notification and I click the notification, it run the app but the app only show blank page, why?
but if I open the app from the mobile menu shortcut it does not matter at all, the app works fine
Could you please help me?
Great article. But having error on WillPresentNotification: Foundation.You_Should_Not_Cal_base_In_This_Metod when I send push notification from firebase on iOS. I follow and Re read many times. Thanks
ReplyDeletedo not call Do not call base.WillPresentNotification
Deletepublic override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action completionHandler)
{
completionHandler(UNNotificationPresentationOptions.Alert | UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Badge);
}
let me now if it works
Hi, thanks for sharing the code. I implemented the code and was able to generate the device token for iOS, but I am not receiving any notifications on the iOS device. Could you help me correct this?
ReplyDeleteFor android if you dont get device token try adding the name of the class in the Service attribute
ReplyDelete[Service(Name = "com.companyname.MyFirebaseMessagingService", Exported = true)]