MAUI Platform Invoke
Use this skill when a MAUI app needs platform APIs that are not already exposed
by a cross-platform MAUI API. Prefer small, testable abstractions over scattered
#if blocks.
Response Checklist
- Define a DI abstraction first (for example
IAppReviewService) and inject it
into app services or view models.
- Mention required permission flow and platform metadata files
(
AndroidManifest.xml, Info.plist, capabilities/entitlements).
- Put lifecycle guidance in
ConfigureLifecycleEvents (AddAndroid, AddiOS,
AddWindows) instead of page constructors.
Choose the Right Extension Point
| Need |
Prefer |
| Existing cross-platform Essentials API covers it |
Microsoft.Maui.ApplicationModel, Devices, Storage, etc. |
| Non-visual platform API or OS service |
DI interface with per-platform implementation |
| Native view/control behavior |
Handler mapper or custom handler |
| Platform lifecycle callback |
ConfigureLifecycleEvents |
| Third-party SDK with many native types |
Slim binding plus a narrow app service |
| One small compile-time constant |
#if or OnPlatform |
Platform Service Pattern
Define an interface in shared code:
public interface IAppReviewService
{
Task RequestReviewAsync(CancellationToken cancellationToken = default);
}
Implement it per platform using target-specific files:
// Platforms/Android/AppReviewService.android.cs
public sealed class AppReviewService : IAppReviewService
{
public Task RequestReviewAsync(CancellationToken cancellationToken = default)
{
// Call Android APIs or a bound SDK here.
return Task.CompletedTask;
}
}
Register only the platforms that have implementations in MauiProgram.cs:
#if ANDROID
builder.Services.AddSingleton<IAppReviewService, AppReviewService>();
#endif
When adding iOS, Mac Catalyst, Windows, or MAUI Labs AppKit support, add the
matching platform implementation file first and then extend the guard, for
example #if IOS || MACCATALYST or #if MACOS.
Inject IAppReviewService into view models or application services. Keep page
constructors simple.
Partial Classes and Conditional Compilation
- Prefer platform-specific files under
Platforms/<Platform>/ for code that
imports native namespaces.
- Use
partial classes when one cross-platform type needs per-platform method
bodies.
- Use
#if ANDROID, #if IOS, #if MACCATALYST, #if IOS || MACCATALYST,
#if MACOS, and #if WINDOWS intentionally. iOS and Mac Catalyst often share
UIKit APIs, but AppKit macOS does not.
- Avoid
Device.RuntimePlatform for behavior that can be decided at compile
time.
Permissions and Capabilities
Before calling a platform API:
- Check whether MAUI has a
Permissions.* helper for the capability.
- Add required manifest, Info.plist, entitlements, or package declarations.
- Request permission from UI-safe code before invoking the service.
- Handle denied/restricted states explicitly and surface user-actionable
recovery instructions.
var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
if (status != PermissionStatus.Granted)
status = await Permissions.RequestAsync<Permissions.Camera>();
if (status != PermissionStatus.Granted)
{
if (Shell.Current is not null)
{
await Shell.Current.DisplayAlert(
"Camera permission required",
"Enable camera access in Settings to use this feature.",
"OK");
}
return;
}
Do not swallow permission failures or return fake success. In a service layer,
return a result such as PermissionStatus or bool and let the caller surface
the denial in UI.
Lifecycle Hooks
Use lifecycle hooks when the native API depends on app/window lifecycle:
builder.ConfigureLifecycleEvents(events =>
{
#if ANDROID
events.AddAndroid(android => android
.OnResume(activity => { /* refresh platform state */ }));
#elif IOS || MACCATALYST
events.AddiOS(ios => ios
.OnActivated(application => { /* refresh platform state */ }));
#elif WINDOWS
events.AddWindows(windows => windows
.OnWindowCreated(window => { /* configure native window */ }));
#endif
});
Keep lifecycle code small. Forward work into registered services when state must
be shared with view models.
Validation Checklist
- A cross-platform interface isolates native API calls.
- Platform implementation files compile only for their intended target.
- Required permissions, manifests, plist entries, entitlements, or capabilities
are documented and added.
- Denied permissions are handled explicitly.
- Native lifecycle subscriptions are paired with cleanup where applicable.
- Visual customization is not implemented as a generic platform service.
1---2name: maui-platform-invoke3description: Add native platform APIs through MAUI services and lifecycle hooks. USE FOR: DI wrappers, permissions, AndroidManifest.xml, Info.plist, entitlements, partial platform files, `ConfigureLifecycleEvents`, choosing services vs handlers vs bindings. DO NOT USE FOR: visual handlers, native SDK bindings, backend.4---56# MAUI Platform Invoke78Use this skill when a MAUI app needs platform APIs that are not already exposed9by a cross-platform MAUI API. Prefer small, testable abstractions over scattered10`#if` blocks.1112## Response Checklist1314- Define a DI abstraction first (for example `IAppReviewService`) and inject it15 into app services or view models.16- Mention required permission flow and platform metadata files17 (`AndroidManifest.xml`, `Info.plist`, capabilities/entitlements).18- Put lifecycle guidance in `ConfigureLifecycleEvents` (`AddAndroid`, `AddiOS`,19 `AddWindows`) instead of page constructors.2021## Choose the Right Extension Point2223| Need | Prefer |24| --- | --- |25| Existing cross-platform Essentials API covers it | `Microsoft.Maui.ApplicationModel`, `Devices`, `Storage`, etc. |26| Non-visual platform API or OS service | DI interface with per-platform implementation |27| Native view/control behavior | Handler mapper or custom handler |28| Platform lifecycle callback | `ConfigureLifecycleEvents` |29| Third-party SDK with many native types | Slim binding plus a narrow app service |30| One small compile-time constant | `#if` or `OnPlatform` |3132## Platform Service Pattern33341. Define an interface in shared code:3536 ```csharp37 public interface IAppReviewService38 {39 Task RequestReviewAsync(CancellationToken cancellationToken = default);40 }41 ```42432. Implement it per platform using target-specific files:4445 ```csharp46 // Platforms/Android/AppReviewService.android.cs47 public sealed class AppReviewService : IAppReviewService48 {49 public Task RequestReviewAsync(CancellationToken cancellationToken = default)50 {51 // Call Android APIs or a bound SDK here.52 return Task.CompletedTask;53 }54 }55 ```56573. Register only the platforms that have implementations in `MauiProgram.cs`:5859 ```csharp60 #if ANDROID61 builder.Services.AddSingleton<IAppReviewService, AppReviewService>();62 #endif63 ```6465 When adding iOS, Mac Catalyst, Windows, or MAUI Labs AppKit support, add the66 matching platform implementation file first and then extend the guard, for67 example `#if IOS || MACCATALYST` or `#if MACOS`.68694. Inject `IAppReviewService` into view models or application services. Keep page70 constructors simple.7172## Partial Classes and Conditional Compilation7374- Prefer platform-specific files under `Platforms/<Platform>/` for code that75 imports native namespaces.76- Use `partial` classes when one cross-platform type needs per-platform method77 bodies.78- Use `#if ANDROID`, `#if IOS`, `#if MACCATALYST`, `#if IOS || MACCATALYST`,79 `#if MACOS`, and `#if WINDOWS` intentionally. iOS and Mac Catalyst often share80 UIKit APIs, but AppKit macOS does not.81- Avoid `Device.RuntimePlatform` for behavior that can be decided at compile82 time.8384## Permissions and Capabilities8586Before calling a platform API:87881. Check whether MAUI has a `Permissions.*` helper for the capability.892. Add required manifest, Info.plist, entitlements, or package declarations.903. Request permission from UI-safe code before invoking the service.914. Handle denied/restricted states explicitly and surface user-actionable92 recovery instructions.9394```csharp95var status = await Permissions.CheckStatusAsync<Permissions.Camera>();96if (status != PermissionStatus.Granted)97 status = await Permissions.RequestAsync<Permissions.Camera>();9899if (status != PermissionStatus.Granted)100{101 if (Shell.Current is not null)102 {103 await Shell.Current.DisplayAlert(104 "Camera permission required",105 "Enable camera access in Settings to use this feature.",106 "OK");107 }108 return;109}110```111112Do not swallow permission failures or return fake success. In a service layer,113return a result such as `PermissionStatus` or `bool` and let the caller surface114the denial in UI.115116## Lifecycle Hooks117118Use lifecycle hooks when the native API depends on app/window lifecycle:119120```csharp121builder.ConfigureLifecycleEvents(events =>122{123#if ANDROID124 events.AddAndroid(android => android125 .OnResume(activity => { /* refresh platform state */ }));126#elif IOS || MACCATALYST127 events.AddiOS(ios => ios128 .OnActivated(application => { /* refresh platform state */ }));129#elif WINDOWS130 events.AddWindows(windows => windows131 .OnWindowCreated(window => { /* configure native window */ }));132#endif133});134```135136Keep lifecycle code small. Forward work into registered services when state must137be shared with view models.138139## Validation Checklist140141- A cross-platform interface isolates native API calls.142- Platform implementation files compile only for their intended target.143- Required permissions, manifests, plist entries, entitlements, or capabilities144 are documented and added.145- Denied permissions are handled explicitly.146- Native lifecycle subscriptions are paired with cleanup where applicable.147- Visual customization is not implemented as a generic platform service.