Plugin.Maui.PushRouter
1.0.1
See the version list below for details.
dotnet add package Plugin.Maui.PushRouter --version 1.0.1
NuGet\Install-Package Plugin.Maui.PushRouter -Version 1.0.1
<PackageReference Include="Plugin.Maui.PushRouter" Version="1.0.1" />
<PackageVersion Include="Plugin.Maui.PushRouter" Version="1.0.1" />
<PackageReference Include="Plugin.Maui.PushRouter" />
paket add Plugin.Maui.PushRouter --version 1.0.1
#r "nuget: Plugin.Maui.PushRouter, 1.0.1"
#:package Plugin.Maui.PushRouter@1.0.1
#addin nuget:?package=Plugin.Maui.PushRouter&version=1.0.1
#tool nuget:?package=Plugin.Maui.PushRouter&version=1.0.1
Plugin.Maui.PushRouter
A .NET MAUI plugin for Android and iOS that routes FCM and APNs notifications to handlers and screens.
The package does not replace Firebase / APNs registration. Your app (or another library) still obtains tokens and shows system notifications. PushRouter takes the payload and:
- Parses FCM
data/ Android Intent extras / APNsuserInfo - Dispatches by
routeortype - Invokes a handler, or opens a Shell page (
//order?id={orderId}) - Queues cold-start taps until
Shellis ready - Deduplicates the same
message_idwhen both the OS tap and your SDK fire
Install
dotnet add package Plugin.Maui.PushRouter
Target frameworks:
net10.0(unit tests / shared)net10.0-androidnet10.0-ios
Register the plugin
builder
.UseMauiApp<App>()
.UsePushRouter(options =>
{
options.EnableLogging = true;
options.RouteKey = "route";
options.TypeKey = "type";
options.NavigateOnTapOnly = true;
options.Map("order", "//order?id={orderId}");
options.Map("chat", "//chat?thread={threadId}");
options.Handle("silent", context =>
{
// Refresh local state. No navigation.
});
});
Resolve IPushRouter from dependency injection, or use PushRouter.Current.
Call PushRouter.Current.MarkReady() after AppShell is created (the sample does this in CreateWindow). UsePushRouter also marks ready on Android resume / iOS activate when Shell.Current exists.
Register Shell routes to match your maps:
Routing.RegisterRoute("order", typeof(OrderPage));
Routing.RegisterRoute("chat", typeof(ChatPage));
Payload contract
Send a route (or type) in the data payload.
FCM
{
"data": {
"route": "order",
"orderId": "1842",
"title": "Order shipped",
"body": "Your order is on the way"
}
}
APNs
{
"aps": {
"alert": {
"title": "New message",
"body": "Alex: are you free?"
}
},
"route": "chat",
"threadId": "thread-22"
}
route may also be a Shell path: "//order?id=1842".
{orderId} tokens in Map are replaced from the payload and URL-encoded.
Feed notifications in
Taps and cold starts are captured automatically:
| Android | iOS | |
|---|---|---|
| User taps a notification | OnCreate / OnNewIntent Intent extras |
UNUserNotificationCenter response |
| App launched from a notification | Same Intent extras | LaunchOptionsRemoteNotificationKey |
| Foreground data message | Host must call HandleReceived |
Delegate WillPresentNotification |
Android (FCM)
UsePushRouter reads the launcher activity Intent. For messages that arrive while the app is in the foreground, forward RemoteMessage.Data from your FirebaseMessagingService:
[Service(Exported = false)]
[IntentFilter(["com.google.firebase.MESSAGING_EVENT"])]
public sealed class AppMessagingService : FirebaseMessagingService
{
public override void OnMessageReceived(RemoteMessage message)
{
PushRouter.Current.HandleReceived(message.Data);
}
}
You can also call PushRouter.HandleIntent(intent) yourself.
Use LaunchMode.SingleTop on MainActivity so a tap does not create a second activity.
iOS (APNs)
UsePushRouter attaches a UNUserNotificationCenter delegate (existing delegates are wrapped) and reads launch options. If you already implement the delegate, wrapping still forwards to your type.
You can also call:
PushRouter.HandleUserInfo(userInfo, PushDelivery.Tapped);
PushRouter.HandleLaunchOptions(launchOptions);
Request notification permission and register for remote notifications in your app. This package does not request permission or manage device tokens.
Handlers vs screens
// Screen: map a key to a Shell path
PushRouter.Current.Map("order", "//order?id={orderId}");
// Handler: custom work, optionally continue to the screen
PushRouter.Current.Handle("order", async (context, token) =>
{
var id = context.Notification["orderId"];
await LoadOrderAsync(id, token);
return PushRouteResult.Navigate;
});
PushRouteResult |
Meaning |
|---|---|
Handled |
Done. No Shell navigation. |
Navigate |
Continue to the mapped screen. |
NotHandled |
Try maps / default route. |
Ignore |
Drop the notification. |
Foreground receives raise Received and run handlers. They do not navigate unless you set NavigateOnTapOnly = false or the handler returns Navigate.
Events
var router = PushRouter.Current;
router.Received += (_, e) => { };
router.Tapped += (_, e) => { };
router.Routed += (_, e) => { };
router.Unhandled += (_, e) => { };
router.Failed += (_, e) => { };
Host app setup
Android
- Add the Firebase / FCM SDK (or another push provider) in the host app.
- Declare
POST_NOTIFICATIONSon Android 13+ if you show notifications. - Keep
MainActivityasSingleTop. - Put routing keys on the FCM data payload so they survive a tap.
iOS
- Enable Push Notifications and the
remote-notificationbackground mode. - Add
aps-environmentin entitlements for device builds. - Custom keys belong next to
aps, not inside it.
Sample
samples/PushRouter.Sample simulates FCM and APNs payloads and opens Order / Chat pages.
dotnet build src/Plugin.Maui.PushRouter/Plugin.Maui.PushRouter.csproj
dotnet pack src/Plugin.Maui.PushRouter/Plugin.Maui.PushRouter.csproj -c Release
dotnet test tests/Plugin.Maui.PushRouter.Tests/Plugin.Maui.PushRouter.Tests.csproj
dotnet build samples/PushRouter.Sample/PushRouter.Sample.csproj -f net10.0-android
Pack
dotnet pack src/Plugin.Maui.PushRouter/Plugin.Maui.PushRouter.csproj -c Release
Packages are written to artifacts/.
Support
If this plugin saved you a weekend of native plumbing, consider buying me a coffee. Your support keeps it maintained, documented, and free.
This library stays open source. A coffee helps cover time for bug fixes, new features, and docs.
| 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.Maui.Controls (>= 10.0.20)
-
net10.0-android36.0
- Microsoft.Maui.Controls (>= 10.0.20)
-
net10.0-ios26.0
- Microsoft.Maui.Controls (>= 10.0.20)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Include the Buy Me a Coffee support section in the package README.