Lifecycle Hooks
Like .NET MAUI, Shiny has always needed a set of platform lifecycle hooks. Many operations within Shiny — permissions, app foregrounding and backgrounding, push notification registration, deep links, activity results — require reacting to events that only the platform itself can raise. Shiny does not take a direct dependency on .NET MAUI; instead it exposes its own lifecycle interfaces that work in MAUI, native iOS/Android, and other .NET hosts.
How It Works
Section titled “How It Works”Shiny’s host wires a platform-specific lifecycle executor into the app startup. Any service you register with the DI container that implements one of the lifecycle sub-interfaces below is automatically resolved and called when the corresponding platform event fires. You never call these methods yourself — just implement the interface and register the service.
// In MauiProgram.cs (or your native host setup)builder.Services.AddSingleton<IIosLifecycle.IContinueActivity, MyUniversalLinkHandler>();builder.Services.AddSingleton<IAndroidLifecycle.IOnActivityNewIntent, MyDeepLinkHandler>();iOS lifecycle interfaces live in Shiny.Hosting.IIosLifecycle. Implement any of the nested sub-interfaces below to hook into the corresponding UIApplicationDelegate or UNUserNotificationCenterDelegate callback.
| Interface | Fires On |
|---|---|
IApplicationLifecycle |
App entering foreground / background |
IOnFinishedLaunching |
FinishedLaunching with launch options |
IContinueActivity |
Universal links & Handoff (ContinueUserActivity) |
IRemoteNotifications |
APNs token registration, registration failure, and silent push delivery |
INotificationHandler |
Foreground notification presentation and user tap responses |
IHandleEventsForBackgroundUrl |
Background NSURLSession completion |
Example — Universal Links
Section titled “Example — Universal Links”using Shiny.Hosting;using Foundation;using UIKit;
public class UniversalLinkHandler : IIosLifecycle.IContinueActivity{ public bool Handle(NSUserActivity activity, UIApplicationRestorationHandler completionHandler) { if (activity.ActivityType == NSUserActivityType.BrowsingWeb) { var url = activity.WebPageUrl?.ToString(); // route the URL inside your app return true; } return false; }}
// Registrationbuilder.Services.AddSingleton<IIosLifecycle.IContinueActivity, UniversalLinkHandler>();Android
Section titled “Android”Android lifecycle interfaces live in Shiny.Hosting.IAndroidLifecycle. The executor observes the Android Application and the currently-attached Activity, so these callbacks fire regardless of which activity is active.
| Interface | Fires On |
|---|---|
IApplicationLifecycle |
App entering foreground / background |
IOnActivityOnCreate |
Activity OnCreate (including saved instance state) |
IOnActivityNewIntent |
Activity OnNewIntent — used for deep links and push taps |
IOnActivityResult |
Activity result callbacks from StartActivityForResult |
IOnActivityRequestPermissionsResult |
Runtime permission request results |
Example — Deep Links
Section titled “Example — Deep Links”using Shiny.Hosting;using Android.App;using Android.Content;
public class DeepLinkHandler : IAndroidLifecycle.IOnActivityNewIntent{ public void Handle(Activity activity, Intent intent) { var data = intent?.DataString; if (!string.IsNullOrEmpty(data)) { // route the URL inside your app } }}
// Registrationbuilder.Services.AddSingleton<IAndroidLifecycle.IOnActivityNewIntent, DeepLinkHandler>();AppKit apps (net10.0-macos) use Shiny.Hosting.IMacLifecycle. It has the same shape as the iOS set, adapted to NSApplicationDelegate:
| Interface | Fires On |
|---|---|
IApplicationLifecycle |
App becoming active / resigning active |
IOnFinishedLaunching |
DidFinishLaunching, with the launch user-info dictionary (may be null) |
IContinueActivity |
Universal links & Handoff |
IRemoteNotifications |
APNs token registration, registration failure, and remote notification delivery |
INotificationHandler |
Foreground notification presentation and user responses |
tvOS uses the iOS interfaces, with one exception: IIosLifecycle.INotificationHandler does not exist on tvOS. A tvOS notification can only change the app icon badge. There is no UNNotificationResponse, and nothing is presented in the foreground. Wrap any implementation of it in #if !TVOS.
Windows, Linux & Blazor
Section titled “Windows, Linux & Blazor”These platforms have no lifecycle executor. Windows and Blazor WebAssembly have no hooks for Shiny to forward. A plain .NET host (console, service, GTK) is never told that it moved to the background, so Shiny doesn’t pretend that it was. ShinyLifecycleTask is a startup task only on Android, iOS, tvOS, Mac Catalyst and macOS. On Windows the class exists but is not an IShinyStartupTask, and on plain net10.0 and Blazor it doesn’t exist at all. In code shared with those targets, implement IShinyStartupTask directly.
Foreground / Background (All Platforms)
Section titled “Foreground / Background (All Platforms)”IApplicationLifecycle exists on IIosLifecycle, IAndroidLifecycle, and IMacLifecycle with the same shape. If you need a single handler that works on every platform, the easiest route is to inherit from ShinyLifecycleTask — it implements the correct interface on each platform and runs as an IShinyStartupTask, so it is automatically instantiated on app launch.
using Shiny;
[Singleton]public class AppPresenceTask : ShinyLifecycleTask{ readonly ILogger<AppPresenceTask> logger;
public AppPresenceTask(ILogger<AppPresenceTask> logger) { this.logger = logger; }
public override void Start() => this.logger.LogInformation("App launched");
protected override void OnStateChanged(bool backgrounding) => this.logger.LogInformation(backgrounding ? "Backgrounded" : "Foregrounded");}
// Registration (alongside AddGeneratedServices())builder.Services.AddGeneratedServices();

