| name | shiny-notifications |
| description | Cross-platform local notification management for .NET MAUI apps using Shiny, supporting scheduled, repeating, and geofence-triggered notifications with channels, badges, and interactive actions. |
| auto_invoke | true |
| triggers | ["local notifications","notification manager","notification channel","notification delegate","push notification","scheduled notification","geofence notification","repeating notification","badge count","notification actions","Shiny.Notifications","INotificationManager","INotificationDelegate","notification permission","notification sound","channel importance"] |
Shiny Notifications
When to Use This Skill
Use this skill when the user needs to:
- Send local notifications (immediate, scheduled, repeating, or geofence-triggered)
- Manage notification channels with importance levels, sounds, and actions
- Handle notification tap responses and interactive action buttons
- Request notification permissions on iOS and Android
- Manage app icon badge counts
- Configure platform-specific notification behavior (Android ongoing, iOS subtitles, etc.)
Library Overview
| Item | Value |
|---|
| NuGet Package | Shiny.Notifications (iOS, Mac Catalyst, Android, macOS, Windows); Shiny.Notifications.Linux (Linux) |
| Primary Namespace | Shiny.Notifications |
| Registration Namespace | Shiny (extension methods on IServiceCollection) |
| Platforms | iOS, Mac Catalyst, Android, macOS, Windows, Linux |
| Dependencies | Shiny.Core, Shiny.Locations, Shiny.Support.Repositories |
Linux
Linux notifications ship in a separate package, Shiny.Notifications.Linux. They are delivered via the freedesktop org.freedesktop.Notifications D-Bus service (GNOME, KDE, XFCE, etc.) and support the same INotificationManager API surface as the other platforms. Scheduled notifications are tracked in-process only — there is no OS-level scheduler like BGTaskScheduler or WorkManager, so the host process must be running for a scheduled notification to fire. Channels are exposed but only a subset of freedesktop hints (urgency, category, image) are actually honoured by most daemons. Geofence triggers and time-sensitive flags are not applicable.
Register with services.AddNotifications<TDelegate>(); from the Shiny namespace — the same call site as the other platforms.
Setup
Register the notification services in your MauiProgram.cs:
using Shiny;
services.AddNotifications();
services.AddNotifications<MyNotificationDelegate>();
On iOS, you can optionally pass an IosConfiguration to control authorization and presentation options:
#if IOS || MACCATALYST
services.AddNotifications<MyNotificationDelegate>(new IosConfiguration(
UNAuthorizationOptions: UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
PresentationOptions: UNNotificationPresentationOptions.Banner | UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Sound
));
#endif
Code Generation Instructions
When generating code that uses Shiny Notifications, follow these conventions:
-
Always request access before sending notifications:
var access = await notificationManager.RequestAccess();
if (access != AccessState.Available)
{
return;
}
-
Use AccessRequestFlags when the notification uses triggers:
AccessRequestFlags.TimeSensitivity for scheduled or repeating notifications.
AccessRequestFlags.LocationAware for geofence-triggered notifications.
- Or use the
RequestRequiredAccess extension method that infers flags from the notification object.
-
A Notification must have a Message set -- validation will throw otherwise.
-
Only one trigger type per notification -- you cannot mix ScheduleDate, RepeatInterval, and Geofence on the same notification.
-
Implement INotificationDelegate for handling user taps:
public class MyNotificationDelegate : INotificationDelegate
{
public async Task OnEntry(NotificationResponse response)
{
}
}
-
Create channels before sending notifications that reference them:
notificationManager.AddChannel(new Channel
{
Identifier = "alerts",
Importance = ChannelImportance.High,
Sound = ChannelSound.High
});
-
Use the convenience Send extension for simple notifications:
await notificationManager.Send("Title", "Message body");
-
For platform-specific properties, use the native subclasses:
- Android:
AndroidNotification and AndroidChannel
- iOS:
AppleNotification and AppleChannel
-
Always inject INotificationManager via constructor injection -- never create instances directly.
-
Use CancelScope wisely when cancelling:
CancelScope.DisplayedOnly -- clears only shown notifications.
CancelScope.Pending -- clears only scheduled/triggered notifications.
CancelScope.All -- clears everything (default).
Namespace Ambiguities
Notification: Both Shiny.Notifications and Shiny.Push define a Notification type. If both packages are referenced in the same project, do NOT add both namespaces as global usings. Use Shiny.Notifications.Notification FQN or a file-level using Shiny.Notifications; directive to disambiguate.
Best Practices
- Always check the
AccessState result before attempting to send notifications.
- Use channels to group notifications by category (e.g., "alerts", "reminders", "messages").
- The default channel (
Channel.Default) always exists with Identifier = "Notifications" and ChannelImportance.Low.
- Do not remove the default channel -- the library will throw an
InvalidOperationException.
- Set
BadgeCount only on immediate notifications (not triggered ones) -- validation will fail otherwise.
- Use
IntervalTrigger with either Interval (raw TimeSpan) or TimeOfDay (daily/weekly recurring), never both.
- For geofence notifications, ensure
Center and Radius are both set on GeofenceTrigger.
- On Android, create a drawable resource named
notification for the default small icon, or set SmallIconResourceName on AndroidNotification.
- Prefer the
RequestRequiredAccess extension method to automatically determine needed permission flags from a Notification object.
- Use
Payload dictionary on Notification to pass custom data that you can read back in your INotificationDelegate.OnEntry.
Reference Files