name: shiny-push description: Guide for implementing push notifications in .NET MAUI apps using Shiny.Push (native FCM/APNs) and Shiny.Push.AzureNotificationHubs auto_invoke: true triggers: - push notification - push notifications - push delegate - push manager - IPushManager - IPushDelegate - firebase push - FCM - APNs - azure notification hub - azure notification hubs - ANH - remote notification - device token - registration token - push tag - push tags - AddPush - AddPushAzureNotificationHubs - PushAccessState - PushNotification - Shiny.Push - shiny push
Shiny Push Notifications
When to Use This Skill
Use this skill when the user needs to:
- Register for push notifications on iOS (APNs) or Android (FCM)
- Handle incoming push notifications (foreground and background)
- Handle push notification tap/entry events
- Manage push notification tags/topics
- Integrate Azure Notification Hubs as a push provider
- Implement a custom push delegate
- Configure Firebase for Android push
- Request push notification permissions
- Unregister from push notifications
- Customize Apple foreground notification presentation
- Build and display Android notifications from push data
Library Overview
| Item | Value |
|---|---|
| NuGet (Native Push) | Shiny.Push |
| NuGet (Azure NH) | Shiny.Push.AzureNotificationHubs |
| Primary Namespace | Shiny.Push |
| Config Namespace | Shiny (extension methods on IServiceCollection) |
| Platforms | iOS (APNs), Android (FCM), Windows (WNS), WebAssembly (experimental) |
Setup
Native Push (FCM on Android, APNs on iOS)
Register in your MauiProgram.cs:
using Shiny;
builder.Services.AddPush<MyPushDelegate>();
On Android, this uses FirebaseConfig with embedded google-services.json by default. To provide Firebase values manually:
#if ANDROID
builder.Services.AddPush<MyPushDelegate>(FirebaseConfig.FromValues(
appId: "your-app-id",
senderId: "your-sender-id",
projectId: "your-project-id",
apiKey: "your-api-key"
));
#else
builder.Services.AddPush<MyPushDelegate>();
#endif
Azure Notification Hubs
Supports iOS (APNs), Android (FCM v1), and Windows (WNS) via a single registration call.
using Shiny;
builder.Services.AddPushAzureNotificationHubs<MyPushDelegate>(
"Endpoint=sb://...;SharedAccessKeyName=...;SharedAccessKey=...",
"your-hub-name"
);
On Android with custom Firebase config:
#if ANDROID
builder.Services.AddPushAzureNotificationHubs<MyPushDelegate>(
"Endpoint=sb://...",
"your-hub-name",
FirebaseConfig.FromValues("appId", "senderId", "projectId", "apiKey")
);
#endif
Code Generation Instructions and Conventions
Always implement
IPushDelegate(or subclassPushDelegate) to handle push events. Register it as a generic type parameter onAddPush<T>()orAddPushAzureNotificationHubs<T>().Request access before using push. Call
IPushManager.RequestAccess()and checkPushAccessState.Status == AccessState.Availablebefore assuming push is working.Use
PushAccessState.Assert()when you want to throw on denied/restricted permissions rather than checking the status manually.Multiple delegates are supported. You can register multiple
IPushDelegateimplementations; all will be called. Register additional delegates as keyed/standard services viaservices.AddSingleton<IPushDelegate, MyOtherPushDelegate>()or tag the class with[Singleton]fromShiny.Extensions.DependencyInjection.Apple-specific customization:
- Cast
IPushManagertoIApplePushManagerfor customUNAuthorizationOptions. - Implement
IApplePushDelegate(extendsIPushDelegate) to control foreground presentation options and background fetch results. - On iOS,
PushNotificationmay be anApplePushNotificationwith access to the rawNSDictionarypayload.
- Cast
Android-specific customization:
PushNotificationreceived inOnReceivedmay be anAndroidPushNotificationwith access to the nativeRemoteMessage.- Use
AndroidPushNotification.CreateBuilder()to build aNotificationCompat.Builderfrom the push data. - Use
AndroidPushNotification.SendDefault(notificationId)for quick notification display. - Configure
FirebaseConfig.DefaultChannelto set a defaultNotificationChannel. - Configure
FirebaseConfig.IntentActionto set a custom intent action for notification taps.
Tags/Topics:
- Check
IPushManager.Tags != null(or usepushManager.IsTagsSupport()) before using tag operations. - Native Firebase on Android supports tags via FCM topic subscriptions.
- Azure Notification Hubs supports tags via installation tags.
- Use extension methods
TrySetTags,TryGetTags,TryRequestAccessWithTagsfor safe tag operations.
- Check
Azure Notification Hubs specifics:
- Implement
IPushInstallationEventto modify theInstallationobject (add templates, tags) before it is sent to ANH. - Use
AzureNotificationConfig.BeforeSendInstallationcallback as an alternative toIPushInstallationEvent. AzureNotificationConfig.ExpirationTimecontrols token expiration. EachRequestAccessor tag update bumps expiration.AzureNotificationConfig.AzureAuthenticationWaitTimeMs(default 1000ms) adds a delay after registration to allow ANH propagation.
- Implement
Namespace conventions: Extension methods on
IServiceCollectionlive in theShinynamespace. All push types live inShiny.Push.Do NOT reference platform-specific types (e.g.,
AndroidPushNotification,ApplePushNotification,IApplePushManager,IApplePushDelegate,FirebaseConfig) in shared/cross-platform code. Guard them with#if ANDROID/#if APPLEpreprocessor directives or use runtime platform checks.
Namespace Ambiguities
Notification: BothShiny.PushandShiny.Notificationsdefine aNotificationtype. If both packages are referenced in the same project, do NOT add both namespaces as global usings. UseShiny.Push.PushNotificationor FQN to disambiguate.
Best Practices
- Always handle
OnNewTokenin your delegate to sync the updated token with your backend server. - Always handle
OnEntryto navigate the user to the appropriate screen when they tap a notification. - Use
OnReceivedfor silent/data-only notifications and background processing. On iOS, ensurecontent-available: 1is set in the push payload for background delivery. - Check
PushAccessState.StatusafterRequestAccess()-- do not assume success. - On Android 13+, the POST_NOTIFICATIONS runtime permission is requested automatically by Shiny during
RequestAccess(). - Prefer
AddPush<TDelegate>()overAddPush()+ manual delegate registration to ensure correct service lifetime. - For Azure Notification Hubs, always test with a sufficient
AzureAuthenticationWaitTimeMsif you encounter "InstallationId not found" errors. - The
RegistrationTokenonIPushManageris the provider-level token (e.g., ANH InstallationId), whileNativeRegistrationTokenis the raw OS token (FCM token or APNs device token). UseRegistrationTokenwhen communicating with your backend.