maui-app-lifecycle — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited maui-app-lifecycle (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 7 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 7 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Handle application state transitions correctly in .NET MAUI. This skill covers the cross-platform Window lifecycle events, their platform-native mappings, and patterns for preserving state across backgrounding and resume cycles.
ConfigureLifecycleEventsA .NET MAUI app moves through four states:
| State | Description |
|---|---|
| Not Running | Process does not exist |
| Running | Foreground, receiving input |
| Deactivated | Visible but lost focus (dialog, split-screen, notification shade) |
| Stopped | Fully backgrounded, UI not visible |
Typical flow: Not Running → Running → Deactivated → Stopped → Running (resumed) or Not Running (terminated).
Microsoft.Maui.Controls.Window exposes six cross-platform events:
| Event | Fires when |
|---|---|
Created | Native window allocated |
Activated | Window receives input focus |
Deactivated | Window loses focus (may still be visible) |
Stopped | Window is no longer visible |
Resumed | Window returns to foreground after Stopped |
Destroying | Native window is being torn down |
Override CreateWindow in your App class and attach event handlers:
public partial class App : Application
{
protected override Window CreateWindow(IActivationState? activationState)
{
var window = base.CreateWindow(activationState);
window.Created += (s, e) => Debug.WriteLine("Created");
window.Activated += (s, e) => Debug.WriteLine("Activated");
window.Deactivated += (s, e) => Debug.WriteLine("Deactivated");
window.Stopped += (s, e) => Debug.WriteLine("Stopped");
window.Resumed += (s, e) => Debug.WriteLine("Resumed");
window.Destroying += (s, e) => Debug.WriteLine("Destroying");
return window;
}
}Create a Window subclass and override the virtual methods:
public class AppWindow : Window
{
public AppWindow(Page page) : base(page) { }
protected override void OnActivated() { /* refresh UI */ }
protected override void OnStopped() { /* save state */ }
protected override void OnResumed() { /* restore state */ }
protected override void OnDestroying() { /* cleanup */ }
}Return it from CreateWindow:
protected override Window CreateWindow(IActivationState? activationState)
=> new AppWindow(new AppShell());Preferences for small values or file serialization for larger state.Stopped entirely.protected override void OnStopped()
{
base.OnStopped();
Preferences.Set("draft_text", _viewModel.DraftText);
Preferences.Set("scroll_y", _viewModel.ScrollY);
}
protected override void OnResumed()
{
base.OnResumed();
_viewModel.DraftText = Preferences.Get("draft_text", string.Empty);
_viewModel.ScrollY = Preferences.Get("scroll_y", 0.0);
}
protected override void OnDestroying()
{
base.OnDestroying();
// Android back-button can skip Stopped
Preferences.Set("draft_text", _viewModel.DraftText);
}| Window Event | Android Callback |
|---|---|
| Created | OnCreate |
| Activated | OnResume |
| Deactivated | OnPause |
| Stopped | OnStop |
| Resumed | OnRestart → OnStart → OnResume |
| Destroying | OnDestroy |
| Window Event | UIKit Callback | AddiOS builder method |
|---|---|---|
| Created | WillFinishLaunching / SceneWillConnect | .WillFinishLaunching() / .SceneWillConnect() |
| Activated | DidBecomeActive | .OnActivated() |
| Deactivated | WillResignActive | .OnResignActivation() |
| Stopped | DidEnterBackground | .DidEnterBackground() |
| Resumed | WillEnterForeground | .WillEnterForeground() |
| Destroying | WillTerminate | .WillTerminate() |
⚠️ The UIKit selector names and theAddiOSbuilder method names differ for activation. There is no.DidBecomeActive()or.WillResignActive()builder method — use.OnActivated()and.OnResignActivation()or the code will not compile.
| Window Event | WinUI Callback |
|---|---|
| Created | OnLaunched |
| Activated | Activated (foreground) |
| Deactivated | Activated (background) |
| Stopped | VisibilityChanged (false) |
| Resumed | VisibilityChanged (true) |
| Destroying | Closed |
Use ConfigureLifecycleEvents in MauiProgram.cs when you need platform-specific callbacks beyond what Window events provide:
builder.ConfigureLifecycleEvents(events =>
{
#if ANDROID
events.AddAndroid(android => android
.OnCreate((activity, bundle) => Debug.WriteLine("Android OnCreate"))
.OnResume(activity => Debug.WriteLine("Android OnResume"))
.OnPause(activity => Debug.WriteLine("Android OnPause"))
.OnStop(activity => Debug.WriteLine("Android OnStop"))
.OnDestroy(activity => Debug.WriteLine("Android OnDestroy")));
#elif IOS || MACCATALYST
events.AddiOS(ios => ios
.OnActivated(app => Debug.WriteLine("iOS OnActivated"))
.OnResignActivation(app => Debug.WriteLine("iOS OnResignActivation"))
.DidEnterBackground(app => Debug.WriteLine("iOS DidEnterBackground"))
.WillEnterForeground(app => Debug.WriteLine("iOS WillEnterForeground")));
#elif WINDOWS
events.AddWindows(windows => windows
.OnLaunched((app, args) => Debug.WriteLine("Windows OnLaunched"))
.OnActivated((window, args) => Debug.WriteLine("Windows Activated"))
.OnClosed((window, args) => Debug.WriteLine("Windows Closed")));
#endif
});Created → Activated. Use OnActivated for logic that must run on every foreground entry, not OnResumed.Deactivated without Stopped. Do not perform heavy saves in OnDeactivated — the app may never actually background.Destroying directly without Stopped. Place critical save logic in both OnStopped and OnDestroying.Window instance fires its own lifecycle events. Do not assume a single global lifecycle.Preferences for quick saves, not database writes.Application.OnStart(), Application.OnSleep(), and Application.OnResume() exist for backward compatibility but bypass Window-level events. In .NET MAUI, prefer Window lifecycle events (OnActivated, OnStopped, OnResumed, etc.) for correct multi-window behavior.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.