Shaunebu.MAUI.FirebasePushNotifications
1.0.2
See the version list below for details.
dotnet add package Shaunebu.MAUI.FirebasePushNotifications --version 1.0.2
NuGet\Install-Package Shaunebu.MAUI.FirebasePushNotifications -Version 1.0.2
<PackageReference Include="Shaunebu.MAUI.FirebasePushNotifications" Version="1.0.2" />
<PackageVersion Include="Shaunebu.MAUI.FirebasePushNotifications" Version="1.0.2" />
<PackageReference Include="Shaunebu.MAUI.FirebasePushNotifications" />
paket add Shaunebu.MAUI.FirebasePushNotifications --version 1.0.2
#r "nuget: Shaunebu.MAUI.FirebasePushNotifications, 1.0.2"
#:package Shaunebu.MAUI.FirebasePushNotifications@1.0.2
#addin nuget:?package=Shaunebu.MAUI.FirebasePushNotifications&version=1.0.2
#tool nuget:?package=Shaunebu.MAUI.FirebasePushNotifications&version=1.0.2
Shaunebu.MAUI.FirebasePushNotifications ππ₯
Overview β¨
Shaunebu.MAUI.FirebasePushNotifications is an enterprise-grade Firebase Cloud Messaging (FCM) integration for .NET MAUI (Android & iOS) with:
First-class MAUI & DI integration
Enterprise observability (logging + telemetry hooks)
Cancellation-friendly APIs (all key operations support
CancellationToken)Robust validation & error handling (google-services.json / GoogleService-Info.plist)
Unified API for:
Token registration / unregistration
Topic subscription management
Notification categories & actions
Notification channel management (Android)
Foreground & background message processing
It is heavily inspired by Plugin.FirebasePushNotifications but modernized and extended for:
.NET 10 + modern MAUI
Enterprise scenarios (telemetry, DI, graceful cancellation, recovery)
Real-world production constraints (iOS 18 quirks, config validation, state recovery)
Feature Comparison π
Libraries Compared
Shaunebu.MAUI.FirebasePushNotifications (this library)
Plugin.FirebasePushNotifications by Thomas Galliker
Shiny.Push (Shiny ecosystem)
Raw Firebase SDK (manual bindings & platform code)
The goal of Shaunebuβs library is not just βyet another wrapperβ, but a modern, MAUI-first, enterprise-friendly abstraction.
High-Level Comparison
| Feature / Aspect | Shaunebu.MAUI.FirebasePushNotifications | Plugin.FirebasePushNotifications | Shiny.Push | Raw Firebase SDK |
|---|---|---|---|---|
| Target Platforms | β MAUI Android & iOS (.NET 10 ready) | β Xamarin / MAUI (depends on branch) | β MAUI / Xamarin | β Native per platform |
| Unified API | β Single cross-platform API | β Yes | β Yes (via Shiny) | β You implement yourself |
| Token Registration / Unregistration | β
With CancellationToken overloads |
β Basic async | β Async | β Manual |
| Topic Management | β Subscribe/Unsubscribe/All with CT & recovery | β Yes | β Yes | β Manual |
| Notification Categories (iOS) | β Strongly typed categories & actions | β Yes | β Yes | β Manual UNNotificationCenter usage |
| Notification Channels (Android) | β Channel groups + default channel guarantee | β Yes | β Yes | β Manual NotificationChannel setup |
| MAUI Lifecycle Integration | β
UseFirebasePushNotifications extension |
β οΈ Usually manual setup | β οΈ Via Shiny bootstrap | β Completely manual |
| Configuration Validation | β Validates google-services.json & GoogleService-Info.plist with rich exceptions | β οΈ Partial / implicit | β οΈ Some | β You must debug yourself |
| Error Handling | β
Dedicated FirebaseAppInitializationException + descriptive messages |
β οΈ Basic | β οΈ Depends | β Raw exceptions |
| State Recovery | β
RecoverStateAsync() (token & topic state) |
β No explicit API | β οΈ Framework-specific | β You build it |
| Cancellation Support | β All core async APIs have CT overloads | β No | β οΈ Partial | β Up to you |
| Telemetry Hooks | β
IFirebasePushTelemetry (TrackEvent / TrackError) |
β | β οΈ Use Shiny telemetry | β You wire telemetry manually |
| Logging Integration | β
ILogger everywhere (nullable logger supported) |
β οΈ Some logging | β οΈ Shiny logging | β Manual |
| iOS 18 / APNs Workarounds | β iOS 18 notification rate limiter workaround | β | β (or custom) | β Manual |
| Notification Handling Abstraction | β
IPushNotificationHandler per platform |
β Similar | β Uses Shiny βjobs/handlersβ | β All in platform code |
| DI-Friendly Design | β
All components registered via MauiAppBuilder & IServiceCollection |
β οΈ Mixed | β Strong | β You wire everything |
| Production Hardening | β Validation + telemetry + recovery + cancellation | β οΈ Solid but older stack | β Good but Shiny-centric | β You must design it |
| Learning Curve | β MAUI-idiomatic, one entry-point | β οΈ Good docs but Xamarin-styled | β οΈ Must adopt Shiny ecosystem | π§ High (native FCM & APNs) |
Installation π¦
dotnet add package Shaunebu.MAUI.FirebasePushNotifications
Or via PackageReference:
<ItemGroup>
<PackageReference Include="Shaunebu.MAUI.FirebasePushNotifications" Version="1.0.0" />
</ItemGroup>
Quick Start π
1. Configure in MauiProgram.cs
using Shaunebu.MAUI.FirebasePushNotifications;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
// ...
builder
.UseMauiApp<App>()
.UseFirebasePushNotifications(options =>
{
// Global options
options.AutoInitEnabled = true;
// Android configuration
options.Android.NotificationActivityType = typeof(MainActivity);
// You can also configure channels/groups here (see below)
// iOS configuration
options.iOS.PresentationOptions =
UNNotificationPresentationOptions.Alert |
UNNotificationPresentationOptions.Badge |
UNNotificationPresentationOptions.Sound;
// Optional: iOS 18 workaround
options.iOS.iOS18Workaround.Enabled = true;
});
// Register your custom handler (optional but recommended)
builder.Services.AddSingleton<IPushNotificationHandler, MyPushNotificationHandler>();
return builder.Build();
}
}
Under the hood this wires lifecycle events, DI registrations, notification channels (Android), and the cross-platform singleton instance.
2. Implement a Notification Handler
using Shaunebu.MAUI.FirebasePushNotifications.Abstractions;
using Shaunebu.MAUI.FirebasePushNotifications.Enums;
public class MyPushNotificationHandler : IPushNotificationHandler
{
private readonly ILogger<MyPushNotificationHandler> _logger;
public MyPushNotificationHandler(ILogger<MyPushNotificationHandler> logger)
=> _logger = logger;
public Task OnNotificationReceivedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
{
_logger.LogInformation("Notification received with category {Category}", categoryType);
// Example: navigate to a page or show an in-app dialog
// ...
return Task.CompletedTask;
}
public Task OnNotificationOpenedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
{
_logger.LogInformation("Notification opened. Category: {Category}", categoryType);
// Handle deep link, navigation, analytics, etc.
return Task.CompletedTask;
}
public Task OnNotificationActionAsync(IDictionary<string, object> data,
string categoryId,
string actionId,
NotificationCategoryType categoryType)
{
_logger.LogInformation("Action clicked: {Category}/{Action}", categoryId, actionId);
// Handle custom actions (e.g. "ACCEPT_ORDER", "MARK_AS_READ")
return Task.CompletedTask;
}
}
3. Register/Unregister for Push Notifications
using Shaunebu.MAUI.FirebasePushNotifications;
public partial class MainPage : ContentPage
{
private readonly IFirebasePushNotification _push;
public MainPage(IFirebasePushNotification push)
{
InitializeComponent();
_push = push;
}
private async void OnRegisterClicked(object sender, EventArgs e)
{
await _push.RegisterForPushNotificationsAsync();
var token = _push.Token;
await DisplayAlert("FCM Token", token ?? "<null>", "OK");
}
private async void OnUnregisterClicked(object sender, EventArgs e)
{
await _push.UnregisterForPushNotificationsAsync();
await DisplayAlert("FCM", "Unregistered from push notifications", "OK");
}
}
π¨ Deep Configuration Validation (Android + iOS)
Enterprise-grade validation β unique to this library
Before initializing Firebase, the library executes a full validation pipeline.
Android Validation
Your library checks:
| Validation | Description |
|---|---|
| google-services.json presence | Ensures file exists under Platforms/Android |
| Build Action = GoogleServicesJson | Mandatory for FCM resource merging |
| google_app_id exists | Extracted from merged Android resources |
| JSON structure integrity | project_id, project_number, mobilesdk_app_id, api key |
| Package name match | Compares JSON package vs MAUI manifest package |
| FirebaseOptions override validation | Ensures consistency with JSON |
| Telemetry reporting | Errors routed to IFirebasePushTelemetry |
Failure Example:
Invalid google-services.json:
Expected package "com.company.app"
Found "com.company.dev"
iOS Validation
| Validation | Description |
|---|---|
| GoogleService-Info.plist presence | Must be included as BundleResource |
| Bundle identifier match | plist BUNDLE_ID must match app bundle |
| Required keys | GOOGLE_APP_ID, GCM_SENDER_ID, API_KEY |
| FirebaseOptions override validation | Required fields validated |
| Telemetry reporting | Errors logged and telemetered |
Failure Example:
MissingGoogleServiceInfoPlist:
Ensure GoogleService-Info.plist is included with Build Action 'BundleResource'.
Strict Mode (Optional)
options.Validation.StrictMode = true;
Strict mode throws immediately on:
bundle mismatches
package mismatches
missing JSON/PLIST
invalid FirebaseOptions
π¦ Payload Normalization Engine (Android + iOS)
The library converts any FCM payload into a normalized flat dictionary:
IDictionary<string, object> data;
Android Supports:
β Java primitives
β Java.Lang.Object[]
β Nested Bundle β flatten
β ArrayList β object[]
β Null-safe fallbacks
β Key prefixing (aps.alert.title)
iOS Supports:
β NSDictionary recursion
β APS parsing
β APS.Alert flattening
β String-safe conversion
Example Final Output:
{
["aps.alert.title"] = "Hello",
["aps.alert.body"] = "Welcome!",
["type"] = "order",
["order_id"] = "123"
}
This is critical for analytics, routing, A/B testing, and multi-platform consistency.
π Security & Hardening
Your library provides:
β Configuration validation (JSON/PLIST)
β Token & topic state recovery
β Telemetry audit trail
β Sandboxed type conversion
β Cancel-safe async operations
β Optional Strict Mode
β iOS 18 rate-limiter protections
These features are enterprise-critical and unique among MAUI FCM libraries.
π Architecture Overview
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Shaunebu.MAUI.FirebasePushNotifications β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Cross-Platform Layer β
β - IFirebasePushNotification β
β - IPushNotificationHandler β
β - IFirebasePushTelemetry β
β - Validation Engine β
β - Token & Topic Recovery β
ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ€
β Android Implementation β iOS Implementation β
β - FirebaseAppHelper β - FirebaseAppHelper β
β - NotificationChannels β - UNUserNotificationCenter Delegate β
β - Intent Processor β - MessagingDelegateImpl β
β - Bundle Parser β - APS/NSDictionary Parser β
ββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββ
π₯ Advanced Usage Scenarios
β Server-driven navigation
Use payload keys like route, screen, or nested routing metadata.
β Multi-tenant topic structures
tenant/{id}/orders
tenant/{id}/notifications
β Dynamic configuration
Override FirebaseOptions in runtime:
white-label apps
feature-flagged environments
β Enriched telemetry
telemetry.TrackEvent("Push.Opened", new { topic, category, openedAt = Now });
β Offline-first behavior
RecoverStateAsync ensures durability after restarts.
Core Concepts & APIs π―
IFirebasePushNotification
Core cross-platform interface you consume in your app:
Task RegisterForPushNotificationsAsync()Task RegisterForPushNotificationsAsync(CancellationToken ct)Task UnregisterForPushNotificationsAsync()Task UnregisterForPushNotificationsAsync(CancellationToken ct)Task SubscribeTopicAsync(string topic)Task SubscribeTopicAsync(string topic, CancellationToken ct)Task SubscribeTopicsAsync(string[] topics)Task SubscribeTopicsAsync(string[] topics, CancellationToken ct)Task UnsubscribeTopicAsync(string topic)Task UnsubscribeTopicAsync(string topic, CancellationToken ct)Task UnsubscribeTopicsAsync(string[] topics)Task UnsubscribeTopicsAsync(string[] topics, CancellationToken ct)Task UnsubscribeAllTopicsAsync()Task UnsubscribeAllTopicsAsync(CancellationToken ct)string Token { get; }(FCM token)Task RecoverStateAsync()(re-apply token and topic state after app restart / re-config)
All major operations have a CancellationToken-aware overload, which is important for enterprise and long-running operations, especially around registration and topic management.
FirebasePushNotificationOptions
Central configuration object passed via UseFirebasePushNotifications:
bool AutoInitEnabledFirebasePushNotificationAndroidOptions Android { get; }FirebasePushNotificationiOSOptions iOS { get; }
Android options (highlights):
Type NotificationActivityTypeβ Activity used to handle notification intentsNotificationChannelGroup[] NotificationChannelGroupsNotificationChannel[] NotificationChannelsFirebaseOptions? FirebaseOptionsβ programmatic override instead of google-services.json
iOS options (highlights):
Firebase.Core.Options? FirebaseOptionsβ programmatic override instead of GoogleService-Info.plistUNNotificationPresentationOptions PresentationOptionsiOS18WorkaroundOptions iOS18Workaround(rate-limit repeatedWillPresentNotificationcalls)
Telemetry Integration: IFirebasePushTelemetry π
To integrate with Application Insights, OpenTelemetry, custom dashboards, etc., implement:
public interface IFirebasePushTelemetry
{
void TrackEvent(string name, IDictionary<string, string?>? properties = null);
void TrackEvent(string name, IDictionary<string, object?>? properties = null);
void TrackError(Exception exception, IDictionary<string, string?>? properties = null);
}
Example: Application Insights Telemetry
public class AppInsightsFirebaseTelemetry : IFirebasePushTelemetry
{
private readonly TelemetryClient _client;
public AppInsightsFirebaseTelemetry(TelemetryClient client)
=> _client = client;
public void TrackEvent(string name, IDictionary<string, string?>? properties = null)
=> _client.TrackEvent(name, properties);
public void TrackEvent(string name, IDictionary<string, object?>? properties = null)
{
var stringProps = properties?.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value?.ToString());
_client.TrackEvent(name, stringProps);
}
public void TrackError(Exception exception, IDictionary<string, string?>? properties = null)
=> _client.TrackException(exception, properties);
}
Register it:
builder.Services.AddSingleton<IFirebasePushTelemetry, AppInsightsFirebaseTelemetry>();
The library will emit events like:
"Firebase.Initialize.Start","Firebase.Initialize.Success""Firebase.Token.Received""Firebase.Topic.Subscribe""Firebase.Intent.Processed"And will call
TrackErroron failures in registration, initialization, etc.
Android Feature Highlights π€
1. Configuration Validation
Before doing any heavy FCM operations, Android will:
Ensure
google_app_idresource existsEnsure it is non-empty
If issues are detected, it throws
FirebaseAppInitializationExceptionwith:Message explaining what is wrong
Logged via
ILoggerOptionally reported via
IFirebasePushTelemetry.TrackError
2. Firebase Initialization Flow
Uses
FirebaseAppHelper.IsFirebaseAppInitialized(context)to check if FCM is already set upIf not initialized:
If
Android.FirebaseOptionsis provided β configure from codeElse β
FirebaseApp.InitializeApp(context)(from google-services.json)
Ensures initialization succeeded, or throws a rich exception
3. Notification Channels
Uses
INotificationChannelsabstraction (defaultNotificationChannelsimplementation)You can configure:
Channel groups (
NotificationChannelGroups)Channels (
NotificationChannels)
If no channels are configured, it ensures a default channel is created so Android 8+ behaves correctly.
4. Intent Processing
ProcessIntent(Activity activity, Intent intent):
Automatically wired via MAUI lifecycle (
OnCreate,OnNewIntent) inUseFirebasePushNotificationsPerforms safety checks:
Skips
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORYSkips
Intent.ActionMain
Checks extras and:
Cancels the related notification when tapped
Calls
HandleNotificationOpenedorHandleNotificationActiondepending on category/action
Sends telemetry:
"Firebase.Intent.Processed"
5. Topic Management (With & Without CancellationToken)
// Simple
await _push.SubscribeTopicAsync("news");
await _push.UnsubscribeTopicAsync("news");
// With CancellationToken
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await _push.SubscribeTopicAsync("news", cts.Token);
Android internally:
Uses
TaskCompletionSource+ FirebaseOnCompleteListenerHonors
CancellationTokenby cancelling theTaskCompletionSourceUpdates
SubscribedTopicspreference atomically
iOS Feature Highlights π
1. Configuration Validation
ValidateFirebaseConfiguration():
If using
iOS.FirebaseOptions(programmatic):- Checks
GoogleAppId&ProjectIdare non-empty
- Checks
Else:
Expects
GoogleService-Info.plistin bundle with correct Build ActionIf missing β throws
MissingGoogleServiceInfoPlist(FirebaseAppInitializationException)
2. Firebase & APNs Initialization
Configures Firebase (
Firebase.Core.App.Configure)Verifies messaging is initialized (
Messaging.SharedInstance)Wire up:
UNUserNotificationCenter.Current.Delegate(custom delegate)Firebase.CloudMessaging.Messaging.SharedInstance.DelegatetoMessagingDelegateImpl
3. Notification Presentation (iOS 14+ & iOS 18 Workaround)
Maps priority from payload (e.g.
"high","low") intoUNNotificationPresentationOptionsiOS 18 workaround:
Prevents repeated
WillPresentNotificationcalls causing spamUses
NotificationRateLimiterwith configurable expiration time
4. Token Handling
RegisteredForRemoteNotifications(NSData deviceToken):Assigns APNs token to FCM
Calls
DidReceiveRegistrationToken
DidReceiveRegistrationToken(string fcmToken):Calls
HandleTokenRefresh(fcmToken)in basePersists token and triggers re-subscription of pending topics
5. Topic Subscription (With Pending Queue)
If APNs token is not ready:
Topic operations are queued in
pendingTopicsAutomatically flushed when
DidReceiveRegistrationTokenexecutes
Supports CT overloads with
WaitAsync(cancellationToken)forSubscribeAsync/UnsubscribeAsync
MAUI Integration Details π±
Lifecycle Events
UseFirebasePushNotifications hooks into platform lifecycle:
iOS
FinishedLaunchingResolves
IPushNotificationHandlerEnsures
IFirebasePushNotification.Currentis instantiated
Android
OnCreate&OnNewIntentResolves
IPushNotificationHandlerif not already setCalls
ProcessIntent(activity, intent)to handle taps & deep links
Service Registrations
UseFirebasePushNotifications also wires:
// Cross-platform
builder.Services.AddSingleton(_ => IFirebasePushNotification.Current);
builder.Services.AddSingleton(_ => INotificationPermissions.Current);
builder.Services.TryAddSingleton<IFirebasePushNotificationPreferences, FirebasePushNotificationPreferences>();
builder.Services.TryAddSingleton<IPreferences>(_ => Preferences.Default);
builder.Services.AddSingleton(defaultOptions);
// Android
builder.Services.AddSingleton(c => INotificationChannels.Current);
builder.Services.TryAddSingleton<INotificationBuilder, NotificationBuilder>();
// iOS
builder.Services.AddSingleton<INotificationChannels, NotificationChannels>();
Sample Usage Scenarios π¨
1. Subscribe a User to Profile-Based Topics
public class UserNotificationService
{
private readonly IFirebasePushNotification _push;
public UserNotificationService(IFirebasePushNotification push)
{
_push = push;
}
public async Task UpdateSubscriptionsAsync(UserProfile profile, CancellationToken ct = default)
{
var topics = new List<string>();
if (profile.IsPremium)
topics.Add("premium");
if (profile.Region is { } region)
topics.Add($"region_{region.ToLowerInvariant()}");
if (profile.AllowsMarketing)
topics.Add("marketing");
await _push.UnsubscribeAllTopicsAsync(ct);
await _push.SubscribeTopicsAsync(topics.ToArray(), ct);
}
}
2. Deep Linking into Pages on Notification Open
public class NavigationPushHandler : IPushNotificationHandler
{
private readonly Shell _shell;
public NavigationPushHandler()
{
_shell = (Shell)Application.Current.MainPage;
}
public Task OnNotificationReceivedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
=> Task.CompletedTask;
public async Task OnNotificationOpenedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
{
if (data.TryGetValue("route", out var routeObj) &&
routeObj is string route &&
!string.IsNullOrWhiteSpace(route))
{
await _shell.GoToAsync(route);
}
}
public Task OnNotificationActionAsync(IDictionary<string, object> data,
string categoryId,
string actionId,
NotificationCategoryType categoryType)
{
// Handle button actions
return Task.CompletedTask;
}
}
3. Integrating Telemetry & Logs for Production
builder.Logging
.AddDebug()
.AddConsole();
builder.Services.AddSingleton<IFirebasePushTelemetry, AppInsightsFirebaseTelemetry>();
The library then:
Logs detailed debug info when
LogLevel.Debugis enabledEmits telemetry for:
Initialization successes/failures
Token fetching
Topic subscription/unsubscription
Intent processing and platform operations
Troubleshooting π§
Missing google-services.json (Android)
Symptoms:
Startup throws
FirebaseAppInitializationExceptionLog message about
google_app_idnot found
Checklist:
google-services.jsonplaced underPlatforms/Android/Build action set to
GoogleServicesJsonPackage name in JSON matches your MAUI Android package (manifest /
ApplicationId)
Missing GoogleService-Info.plist (iOS)
Symptoms:
App throws
MissingGoogleServiceInfoPlistLogs mention incorrect Build Action
Checklist:
GoogleService-Info.plistincluded in iOS projectBuild Action:
BundleResourceBundle ID in the plist matches your app bundle
Notifications Not Arriving in Foreground (iOS)
Check
options.iOS.PresentationOptions(alerts/banners/list)Ensure UNUserNotificationCenter delegate is not overwritten by your app
(if you need a custom delegate, you must integrate with the libraryβs delegate)
Topics Not Subscribed (iOS)
Ensure APNs token is available (some operations are queued until token is ready)
You can debug
pendingTopicsby enablingLogLevel.DebugCheck for typos or empty topic names (library will throw for empty names)
API Reference (High-Level) π
IFirebasePushNotification
| Member | Description |
|---|---|
Task RegisterForPushNotificationsAsync() |
Configure platform, request permissions and register for FCM push notifications |
Task RegisterForPushNotificationsAsync(CancellationToken) |
CT-aware overload |
Task UnregisterForPushNotificationsAsync() |
Disable AutoInit, unregister push, clear token |
Task UnregisterForPushNotificationsAsync(CancellationToken) |
CT-aware |
Task SubscribeTopicAsync(string) |
Subscribe to a single FCM topic |
Task SubscribeTopicAsync(string, CancellationToken) |
CT-aware |
Task SubscribeTopicsAsync(string[]) |
Subscribe to multiple topics |
Task SubscribeTopicsAsync(string[], CancellationToken) |
CT-aware |
Task UnsubscribeTopicAsync(string) |
Unsubscribe from topic |
Task UnsubscribeTopicAsync(string, CancellationToken) |
CT-aware |
Task UnsubscribeTopicsAsync(string[]) |
Multiple topics |
Task UnsubscribeTopicsAsync(string[], CancellationToken) |
CT-aware |
Task UnsubscribeAllTopicsAsync() |
Clear all topics |
Task UnsubscribeAllTopicsAsync(CancellationToken) |
CT-aware |
Task RecoverStateAsync() |
Re-apply stored token/topics after restart |
string Token { get; } |
Current FCM token (if available) |
Migration Guide π
Migrating from Plugin.FirebasePushNotifications
Conceptually very similar, but:
Register via
UseFirebasePushNotificationsinstead of manualCrossFirebasePushNotificationbootstrapReplace
CrossFirebasePushNotification.Currentwith DI-injectedIFirebasePushNotificationUpdate handlers to the new
IPushNotificationHandlerinterfaceOptional but recommended:
Use
IFirebasePushTelemetryfor events/errorsUse CT overloads for operations invoked from UI/viewmodels
Migrating from Raw Firebase SDK
You can remove:
Custom
FirebaseMessagingServiceglue you createdManual
UNUserNotificationCenterdelegate code (if you used FCM swizzling)Custom preferences storage for token/topics
And instead:
Use
UseFirebasePushNotifications+IFirebasePushNotificationImplement
IPushNotificationHandlerto handle your app-level behavior
License π
This project is licensed under the MIT License. Shaunebu.MAUI.FirebasePushNotifications ππ₯ Platform MAUI License Status
Resilience Observability
NuGet Version
Android iOS Enterprise
Support
Overview β¨ Shaunebu.MAUI.FirebasePushNotifications is an enterprise-grade Firebase Cloud Messaging (FCM) integration for .NET MAUI (Android & iOS) with:
First-class MAUI & DI integration
Enterprise observability (logging + telemetry hooks)
Cancellation-friendly APIs (all key operations support CancellationToken)
Robust validation & error handling (google-services.json / GoogleService-Info.plist)
Unified API for:
Token registration / unregistration
Topic subscription management
Notification categories & actions
Notification channel management (Android)
Foreground & background message processing
It is heavily inspired by Plugin.FirebasePushNotifications but modernized and extended for:
.NET 10 + modern MAUI
Enterprise scenarios (telemetry, DI, graceful cancellation, recovery)
Real-world production constraints (iOS 18 quirks, config validation, state recovery)
Feature Comparison π Libraries Compared Shaunebu.MAUI.FirebasePushNotifications (this library)
Plugin.FirebasePushNotifications by Thomas Galliker
Shiny.Push (Shiny ecosystem)
Raw Firebase SDK (manual bindings & platform code)
The goal of Shaunebuβs library is not just βyet another wrapperβ, but a modern, MAUI-first, enterprise-friendly abstraction.
High-Level Comparison Feature / Aspect Shaunebu.MAUI.FirebasePushNotifications Plugin.FirebasePushNotifications Shiny.Push Raw Firebase SDK Target Platforms β MAUI Android & iOS (.NET 10 ready) β Xamarin / MAUI (depends on branch) β MAUI / Xamarin β Native per platform Unified API β Single cross-platform API β Yes β Yes (via Shiny) β You implement yourself Token Registration / Unregistration β With CancellationToken overloads β Basic async β Async β Manual Topic Management β Subscribe/Unsubscribe/All with CT & recovery β Yes β Yes β Manual Notification Categories (iOS) β Strongly typed categories & actions β Yes β Yes β Manual UNNotificationCenter usage Notification Channels (Android) β Channel groups + default channel guarantee β Yes β Yes β Manual NotificationChannel setup MAUI Lifecycle Integration β UseFirebasePushNotifications extension β οΈ Usually manual setup β οΈ Via Shiny bootstrap β Completely manual Configuration Validation β Validates google-services.json & GoogleService-Info.plist with rich exceptions β οΈ Partial / implicit β οΈ Some β You must debug yourself Error Handling β Dedicated FirebaseAppInitializationException + descriptive messages β οΈ Basic β οΈ Depends β Raw exceptions State Recovery β RecoverStateAsync() (token & topic state) β No explicit API β οΈ Framework-specific β You build it Cancellation Support β All core async APIs have CT overloads β No β οΈ Partial β Up to you Telemetry Hooks β IFirebasePushTelemetry (TrackEvent / TrackError) β β οΈ Use Shiny telemetry β You wire telemetry manually Logging Integration β ILogger everywhere (nullable logger supported) β οΈ Some logging β οΈ Shiny logging β Manual iOS 18 / APNs Workarounds β iOS 18 notification rate limiter workaround β β (or custom) β Manual Notification Handling Abstraction β IPushNotificationHandler per platform β Similar β Uses Shiny βjobs/handlersβ β All in platform code DI-Friendly Design β All components registered via MauiAppBuilder & IServiceCollection β οΈ Mixed β Strong β You wire everything Production Hardening β Validation + telemetry + recovery + cancellation β οΈ Solid but older stack β Good but Shiny-centric β You must design it Learning Curve β MAUI-idiomatic, one entry-point β οΈ Good docs but Xamarin-styled β οΈ Must adopt Shiny ecosystem π§ High (native FCM & APNs) Installation π¦
dotnet add package Shaunebu.MAUI.FirebasePushNotifications Or via PackageReference:
<ItemGroup> <PackageReference Include="Shaunebu.MAUI.FirebasePushNotifications" Version="1.0.0" /> </ItemGroup> Quick Start π
- Configure in MauiProgram.cs
using Shaunebu.MAUI.FirebasePushNotifications;
public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder();
// ...
builder
.UseMauiApp<App>()
.UseFirebasePushNotifications(options =>
{
// Global options
options.AutoInitEnabled = true;
// Android configuration
options.Android.NotificationActivityType = typeof(MainActivity);
// You can also configure channels/groups here (see below)
// iOS configuration
options.iOS.PresentationOptions =
UNNotificationPresentationOptions.Alert |
UNNotificationPresentationOptions.Badge |
UNNotificationPresentationOptions.Sound;
// Optional: iOS 18 workaround
options.iOS.iOS18Workaround.Enabled = true;
});
// Register your custom handler (optional but recommended)
builder.Services.AddSingleton<IPushNotificationHandler, MyPushNotificationHandler>();
return builder.Build();
}
} Under the hood this wires lifecycle events, DI registrations, notification channels (Android), and the cross-platform singleton instance.
- Implement a Notification Handler
using Shaunebu.MAUI.FirebasePushNotifications.Abstractions; using Shaunebu.MAUI.FirebasePushNotifications.Enums;
public class MyPushNotificationHandler : IPushNotificationHandler { private readonly ILogger<MyPushNotificationHandler> _logger;
public MyPushNotificationHandler(ILogger<MyPushNotificationHandler> logger)
=> _logger = logger;
public Task OnNotificationReceivedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
{
_logger.LogInformation("Notification received with category {Category}", categoryType);
// Example: navigate to a page or show an in-app dialog
// ...
return Task.CompletedTask;
}
public Task OnNotificationOpenedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
{
_logger.LogInformation("Notification opened. Category: {Category}", categoryType);
// Handle deep link, navigation, analytics, etc.
return Task.CompletedTask;
}
public Task OnNotificationActionAsync(IDictionary<string, object> data,
string categoryId,
string actionId,
NotificationCategoryType categoryType)
{
_logger.LogInformation("Action clicked: {Category}/{Action}", categoryId, actionId);
// Handle custom actions (e.g. "ACCEPT_ORDER", "MARK_AS_READ")
return Task.CompletedTask;
}
} 3. Register/Unregister for Push Notifications
using Shaunebu.MAUI.FirebasePushNotifications;
public partial class MainPage : ContentPage { private readonly IFirebasePushNotification _push;
public MainPage(IFirebasePushNotification push)
{
InitializeComponent();
_push = push;
}
private async void OnRegisterClicked(object sender, EventArgs e)
{
await _push.RegisterForPushNotificationsAsync();
var token = _push.Token;
await DisplayAlert("FCM Token", token ?? "<null>", "OK");
}
private async void OnUnregisterClicked(object sender, EventArgs e)
{
await _push.UnregisterForPushNotificationsAsync();
await DisplayAlert("FCM", "Unregistered from push notifications", "OK");
}
} π¨ Deep Configuration Validation (Android + iOS) Enterprise-grade validation β unique to this library Before initializing Firebase, the library executes a full validation pipeline.
Android Validation Your library checks:
Validation Description google-services.json presence Ensures file exists under Platforms/Android Build Action = GoogleServicesJson Mandatory for FCM resource merging google_app_id exists Extracted from merged Android resources JSON structure integrity project_id, project_number, mobilesdk_app_id, api key Package name match Compares JSON package vs MAUI manifest package FirebaseOptions override validation Ensures consistency with JSON Telemetry reporting Errors routed to IFirebasePushTelemetry Failure Example:
Invalid google-services.json: Expected package "com.company.app" Found "com.company.dev" iOS Validation Validation Description GoogleService-Info.plist presence Must be included as BundleResource Bundle identifier match plist BUNDLE_ID must match app bundle Required keys GOOGLE_APP_ID, GCM_SENDER_ID, API_KEY FirebaseOptions override validation Required fields validated Telemetry reporting Errors logged and telemetered Failure Example:
MissingGoogleServiceInfoPlist: Ensure GoogleService-Info.plist is included with Build Action 'BundleResource'. Strict Mode (Optional)
options.Validation.StrictMode = true; Strict mode throws immediately on:
bundle mismatches
package mismatches
missing JSON/PLIST
invalid FirebaseOptions
π¦ Payload Normalization Engine (Android + iOS) The library converts any FCM payload into a normalized flat dictionary:
IDictionary<string, object> data; Android Supports: β Java primitives β Java.Lang.Object[] β Nested Bundle β flatten β ArrayList β object[] β Null-safe fallbacks β Key prefixing (aps.alert.title)
iOS Supports: β NSDictionary recursion β APS parsing β APS.Alert flattening β String-safe conversion Example Final Output:
{ ["aps.alert.title"] = "Hello", ["aps.alert.body"] = "Welcome!", ["type"] = "order", ["order_id"] = "123" } This is critical for analytics, routing, A/B testing, and multi-platform consistency.
π Security & Hardening Your library provides:
β Configuration validation (JSON/PLIST) β Token & topic state recovery β Telemetry audit trail β Sandboxed type conversion β Cancel-safe async operations β Optional Strict Mode β iOS 18 rate-limiter protections These features are enterprise-critical and unique among MAUI FCM libraries.
π Architecture Overview
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β Shaunebu.MAUI.FirebasePushNotifications β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β Cross-Platform Layer β β - IFirebasePushNotification β β - IPushNotificationHandler β β - IFirebasePushTelemetry β β - Validation Engine β β - Token & Topic Recovery β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ€ β Android Implementation β iOS Implementation β β - FirebaseAppHelper β - FirebaseAppHelper β β - NotificationChannels β - UNUserNotificationCenter Delegate β β - Intent Processor β - MessagingDelegateImpl β β - Bundle Parser β - APS/NSDictionary Parser β ββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββ π₯ Advanced Usage Scenarios β Server-driven navigation Use payload keys like route, screen, or nested routing metadata.
β Multi-tenant topic structures
tenant/{id}/orders tenant/{id}/notifications β Dynamic configuration Override FirebaseOptions in runtime:
white-label apps
feature-flagged environments
β Enriched telemetry
telemetry.TrackEvent("Push.Opened", new { topic, category, openedAt = Now }); β Offline-first behavior RecoverStateAsync ensures durability after restarts.
Core Concepts & APIs π― IFirebasePushNotification Core cross-platform interface you consume in your app:
Task RegisterForPushNotificationsAsync()
Task RegisterForPushNotificationsAsync(CancellationToken ct)
Task UnregisterForPushNotificationsAsync()
Task UnregisterForPushNotificationsAsync(CancellationToken ct)
Task SubscribeTopicAsync(string topic)
Task SubscribeTopicAsync(string topic, CancellationToken ct)
Task SubscribeTopicsAsync(string[] topics)
Task SubscribeTopicsAsync(string[] topics, CancellationToken ct)
Task UnsubscribeTopicAsync(string topic)
Task UnsubscribeTopicAsync(string topic, CancellationToken ct)
Task UnsubscribeTopicsAsync(string[] topics)
Task UnsubscribeTopicsAsync(string[] topics, CancellationToken ct)
Task UnsubscribeAllTopicsAsync()
Task UnsubscribeAllTopicsAsync(CancellationToken ct)
string Token { get; } (FCM token)
Task RecoverStateAsync() (re-apply token and topic state after app restart / re-config)
All major operations have a CancellationToken-aware overload, which is important for enterprise and long-running operations, especially around registration and topic management.
FirebasePushNotificationOptions Central configuration object passed via UseFirebasePushNotifications:
bool AutoInitEnabled
FirebasePushNotificationAndroidOptions Android { get; }
FirebasePushNotificationiOSOptions iOS { get; }
Android options (highlights):
Type NotificationActivityType β Activity used to handle notification intents
NotificationChannelGroup[] NotificationChannelGroups
NotificationChannel[] NotificationChannels
FirebaseOptions? FirebaseOptions β programmatic override instead of google-services.json
iOS options (highlights):
Firebase.Core.Options? FirebaseOptions β programmatic override instead of GoogleService-Info.plist
UNNotificationPresentationOptions PresentationOptions
iOS18WorkaroundOptions iOS18Workaround (rate-limit repeated WillPresentNotification calls)
Telemetry Integration: IFirebasePushTelemetry π To integrate with Application Insights, OpenTelemetry, custom dashboards, etc., implement:
public interface IFirebasePushTelemetry { void TrackEvent(string name, IDictionary<string, string?>? properties = null); void TrackEvent(string name, IDictionary<string, object?>? properties = null); void TrackError(Exception exception, IDictionary<string, string?>? properties = null); } Example: Application Insights Telemetry
public class AppInsightsFirebaseTelemetry : IFirebasePushTelemetry { private readonly TelemetryClient _client;
public AppInsightsFirebaseTelemetry(TelemetryClient client)
=> _client = client;
public void TrackEvent(string name, IDictionary<string, string?>? properties = null)
=> _client.TrackEvent(name, properties);
public void TrackEvent(string name, IDictionary<string, object?>? properties = null)
{
var stringProps = properties?.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value?.ToString());
_client.TrackEvent(name, stringProps);
}
public void TrackError(Exception exception, IDictionary<string, string?>? properties = null)
=> _client.TrackException(exception, properties);
} Register it:
builder.Services.AddSingleton<IFirebasePushTelemetry, AppInsightsFirebaseTelemetry>(); The library will emit events like:
"Firebase.Initialize.Start", "Firebase.Initialize.Success"
"Firebase.Token.Received"
"Firebase.Topic.Subscribe"
"Firebase.Intent.Processed"
And will call TrackError on failures in registration, initialization, etc.
Android Feature Highlights π€
- Configuration Validation Before doing any heavy FCM operations, Android will:
Ensure google_app_id resource exists
Ensure it is non-empty
If issues are detected, it throws FirebaseAppInitializationException with:
Message explaining what is wrong
Logged via ILogger
Optionally reported via IFirebasePushTelemetry.TrackError
- Firebase Initialization Flow Uses FirebaseAppHelper.IsFirebaseAppInitialized(context) to check if FCM is already set up
If not initialized:
If Android.FirebaseOptions is provided β configure from code
Else β FirebaseApp.InitializeApp(context) (from google-services.json)
Ensures initialization succeeded, or throws a rich exception
- Notification Channels Uses INotificationChannels abstraction (default NotificationChannels implementation)
You can configure:
Channel groups (NotificationChannelGroups)
Channels (NotificationChannels)
If no channels are configured, it ensures a default channel is created so Android 8+ behaves correctly.
- Intent Processing ProcessIntent(Activity activity, Intent intent):
Automatically wired via MAUI lifecycle (OnCreate, OnNewIntent) in UseFirebasePushNotifications
Performs safety checks:
Skips FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
Skips Intent.ActionMain
Checks extras and:
Cancels the related notification when tapped
Calls HandleNotificationOpened or HandleNotificationAction depending on category/action
Sends telemetry: "Firebase.Intent.Processed"
- Topic Management (With & Without CancellationToken)
// Simple await _push.SubscribeTopicAsync("news"); await _push.UnsubscribeTopicAsync("news");
// With CancellationToken using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); await _push.SubscribeTopicAsync("news", cts.Token); Android internally:
Uses TaskCompletionSource + Firebase OnCompleteListener
Honors CancellationToken by cancelling the TaskCompletionSource
Updates SubscribedTopics preference atomically
iOS Feature Highlights π
- Configuration Validation ValidateFirebaseConfiguration():
If using iOS.FirebaseOptions (programmatic):
Checks GoogleAppId & ProjectId are non-empty Else:
Expects GoogleService-Info.plist in bundle with correct Build Action
If missing β throws MissingGoogleServiceInfoPlist (FirebaseAppInitializationException)
- Firebase & APNs Initialization Configures Firebase (Firebase.Core.App.Configure)
Verifies messaging is initialized (Messaging.SharedInstance)
Wire up:
UNUserNotificationCenter.Current.Delegate (custom delegate)
Firebase.CloudMessaging.Messaging.SharedInstance.Delegate to MessagingDelegateImpl
- Notification Presentation (iOS 14+ & iOS 18 Workaround) Maps priority from payload (e.g. "high", "low") into UNNotificationPresentationOptions
iOS 18 workaround:
Prevents repeated WillPresentNotification calls causing spam
Uses NotificationRateLimiter with configurable expiration time
- Token Handling RegisteredForRemoteNotifications(NSData deviceToken):
Assigns APNs token to FCM
Calls DidReceiveRegistrationToken
DidReceiveRegistrationToken(string fcmToken):
Calls HandleTokenRefresh(fcmToken) in base
Persists token and triggers re-subscription of pending topics
- Topic Subscription (With Pending Queue) If APNs token is not ready:
Topic operations are queued in pendingTopics
Automatically flushed when DidReceiveRegistrationToken executes
Supports CT overloads with WaitAsync(cancellationToken) for SubscribeAsync / UnsubscribeAsync
MAUI Integration Details π± Lifecycle Events UseFirebasePushNotifications hooks into platform lifecycle:
iOS
FinishedLaunching Resolves IPushNotificationHandler
Ensures IFirebasePushNotification.Current is instantiated
Android
OnCreate & OnNewIntent Resolves IPushNotificationHandler if not already set
Calls ProcessIntent(activity, intent) to handle taps & deep links
Service Registrations UseFirebasePushNotifications also wires:
// Cross-platform builder.Services.AddSingleton(_ β IFirebasePushNotification.Current); builder.Services.AddSingleton(_ β INotificationPermissions.Current); builder.Services.TryAddSingleton<IFirebasePushNotificationPreferences, FirebasePushNotificationPreferences>(); builder.Services.TryAddSingleton<IPreferences>(_ β Preferences.Default); builder.Services.AddSingleton(defaultOptions);
// Android builder.Services.AddSingleton(c β INotificationChannels.Current); builder.Services.TryAddSingleton<INotificationBuilder, NotificationBuilder>();
// iOS builder.Services.AddSingleton<INotificationChannels, NotificationChannels>(); Sample Usage Scenarios π¨
- Subscribe a User to Profile-Based Topics
public class UserNotificationService { private readonly IFirebasePushNotification _push;
public UserNotificationService(IFirebasePushNotification push)
{
_push = push;
}
public async Task UpdateSubscriptionsAsync(UserProfile profile, CancellationToken ct = default)
{
var topics = new List<string>();
if (profile.IsPremium)
topics.Add("premium");
if (profile.Region is { } region)
topics.Add($"region_{region.ToLowerInvariant()}");
if (profile.AllowsMarketing)
topics.Add("marketing");
await _push.UnsubscribeAllTopicsAsync(ct);
await _push.SubscribeTopicsAsync(topics.ToArray(), ct);
}
} 2. Deep Linking into Pages on Notification Open
public class NavigationPushHandler : IPushNotificationHandler { private readonly Shell _shell;
public NavigationPushHandler()
{
_shell = (Shell)Application.Current.MainPage;
}
public Task OnNotificationReceivedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
=> Task.CompletedTask;
public async Task OnNotificationOpenedAsync(IDictionary<string, object> data,
NotificationCategoryType categoryType)
{
if (data.TryGetValue("route", out var routeObj) &&
routeObj is string route &&
!string.IsNullOrWhiteSpace(route))
{
await _shell.GoToAsync(route);
}
}
public Task OnNotificationActionAsync(IDictionary<string, object> data,
string categoryId,
string actionId,
NotificationCategoryType categoryType)
{
// Handle button actions
return Task.CompletedTask;
}
} 3. Integrating Telemetry & Logs for Production
builder.Logging .AddDebug() .AddConsole();
builder.Services.AddSingleton<IFirebasePushTelemetry, AppInsightsFirebaseTelemetry>(); The library then:
Logs detailed debug info when LogLevel.Debug is enabled
Emits telemetry for:
Initialization successes/failures
Token fetching
Topic subscription/unsubscription
Intent processing and platform operations
Troubleshooting π§ Missing google-services.json (Android) Symptoms:
Startup throws FirebaseAppInitializationException
Log message about google_app_id not found
Checklist:
google-services.json placed under Platforms/Android/
Build action set to GoogleServicesJson
Package name in JSON matches your MAUI Android package (manifest / ApplicationId)
Missing GoogleService-Info.plist (iOS) Symptoms:
App throws MissingGoogleServiceInfoPlist
Logs mention incorrect Build Action
Checklist:
GoogleService-Info.plist included in iOS project
Build Action: BundleResource
Bundle ID in the plist matches your app bundle
Notifications Not Arriving in Foreground (iOS) Check options.iOS.PresentationOptions (alerts/banners/list)
Ensure UNUserNotificationCenter delegate is not overwritten by your app (if you need a custom delegate, you must integrate with the libraryβs delegate)
Topics Not Subscribed (iOS) Ensure APNs token is available (some operations are queued until token is ready)
You can debug pendingTopics by enabling LogLevel.Debug
Check for typos or empty topic names (library will throw for empty names)
API Reference (High-Level) π IFirebasePushNotification Member Description Task RegisterForPushNotificationsAsync() Configure platform, request permissions and register for FCM push notifications Task RegisterForPushNotificationsAsync(CancellationToken) CT-aware overload Task UnregisterForPushNotificationsAsync() Disable AutoInit, unregister push, clear token Task UnregisterForPushNotificationsAsync(CancellationToken) CT-aware Task SubscribeTopicAsync(string) Subscribe to a single FCM topic Task SubscribeTopicAsync(string, CancellationToken) CT-aware Task SubscribeTopicsAsync(string[]) Subscribe to multiple topics Task SubscribeTopicsAsync(string[], CancellationToken) CT-aware Task UnsubscribeTopicAsync(string) Unsubscribe from topic Task UnsubscribeTopicAsync(string, CancellationToken) CT-aware Task UnsubscribeTopicsAsync(string[]) Multiple topics Task UnsubscribeTopicsAsync(string[], CancellationToken) CT-aware Task UnsubscribeAllTopicsAsync() Clear all topics Task UnsubscribeAllTopicsAsync(CancellationToken) CT-aware Task RecoverStateAsync() Re-apply stored token/topics after restart string Token { get; } Current FCM token (if available) Migration Guide π Migrating from Plugin.FirebasePushNotifications Conceptually very similar, but:
Register via UseFirebasePushNotifications instead of manual CrossFirebasePushNotification bootstrap
Replace CrossFirebasePushNotification.Current with DI-injected IFirebasePushNotification
Update handlers to the new IPushNotificationHandler interface
Optional but recommended:
Use IFirebasePushTelemetry for events/errors
Use CT overloads for operations invoked from UI/viewmodels
Migrating from Raw Firebase SDK You can remove:
Custom FirebaseMessagingService glue you created
Manual UNUserNotificationCenter delegate code (if you used FCM swizzling)
Custom preferences storage for token/topics
And instead:
Use UseFirebasePushNotifications + IFirebasePushNotification
Implement IPushNotificationHandler to handle your app-level behavior
License π This project is licensed under the MIT License.
Saved page with message 'Updated Shaunebu.MAUI.FirebasePushNotifications (not published) ~' Showing filters 1 through 1
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Maui.Controls (>= 10.0.0)
- Newtonsoft.Json (>= 13.0.4)
-
net10.0-android36.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Maui.Controls (>= 10.0.0)
- Newtonsoft.Json (>= 13.0.4)
- Xamarin.AndroidX.Activity (>= 1.10.1.3)
- Xamarin.AndroidX.Activity.Ktx (>= 1.10.1.3)
- Xamarin.Firebase.Common (>= 120.3.3.1)
- Xamarin.Firebase.Messaging (>= 123.1.2.2)
- Xamarin.GooglePlayServices.Tasks (>= 118.0.2.3)
-
net10.0-ios26.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Maui.Controls (>= 10.0.0)
- Newtonsoft.Json (>= 13.0.4)
- Xamarin.Firebase.iOS.CloudMessaging (>= 8.10.0.3)
- Xamarin.Firebase.iOS.Core (>= 8.10.0.3)
- Xamarin.Firebase.iOS.Installations (>= 8.10.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.