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>(); #endifWhen 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 || MACCATALYSTor#if MACOS. -
Inject
IAppReviewServiceinto 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
partialclasses when one cross-platform type needs per-platform method bodies. - Use
#if ANDROID,#if IOS,#if MACCATALYST,#if IOS || MACCATALYST,#if MACOS, and#if WINDOWSintentionally. iOS and Mac Catalyst often share UIKit APIs, but AppKit macOS does not. - Avoid
Device.RuntimePlatformfor 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.