npx claudepluginhub davidortinau/maui-skills --plugin maui-skillsThis skill uses the workspace's default tool permissions.
```csharp
Guides calling platform-specific native APIs in .NET MAUI apps using partial classes, conditional compilation, multi-targeting, and DI patterns for Android, iOS, Mac Catalyst, Windows.
Guides .NET MAUI app lifecycle: states, Window events (Created/Activated/Deactivated/Stopped/Resumed/Destroying), platform mappings, backgrounding/resume, state preservation.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Share bugs, ideas, or general feedback.
// ❌ Shows prompt even if already granted
var status = await Permissions.RequestAsync<Permissions.Camera>();
// ✅ Check first — avoids unnecessary prompts
var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
if (status != PermissionStatus.Granted)
status = await Permissions.RequestAsync<Permissions.Camera>();
Permission APIs are async and require a UI context. Constructors can't await.
// ❌ Blocks the UI thread or throws
public MyViewModel()
{
var status = Permissions.RequestAsync<Permissions.Camera>().Result;
}
// ✅ Use OnAppearing, a command, or async initialization
protected override async void OnAppearing()
{
await CheckAndRequestPermissionAsync<Permissions.Camera>();
}
// ❌ Only checks for Granted — misses edge cases
if (status == PermissionStatus.Granted) { /* proceed */ }
// ✅ Handle all relevant statuses
switch (status)
{
case PermissionStatus.Granted: /* proceed */ break;
case PermissionStatus.Limited: /* iOS partial access */ break;
case PermissionStatus.Denied:
case PermissionStatus.Restricted:
await ShowSettingsPromptAsync(); break;
}
iOS shows the system permission dialog only once per permission, ever. After denial, RequestAsync returns Denied immediately without showing UI. You must guide the user to Settings → App → Permission.
ShouldShowRationale returns true only after a prior denial (but not after "Don't ask again"). Use it to show explanatory UI before re-requesting:
if (Permissions.ShouldShowRationale<Permissions.Camera>())
{
await Shell.Current.DisplayAlert("Permission needed",
"Camera access is required to scan barcodes.", "OK");
}
status = await Permissions.RequestAsync<Permissions.Camera>();
On Android 13+, StorageRead and StorageWrite always return Granted (scoped storage makes them meaningless). Use granular media permissions instead:
// ❌ Always returns Granted on API 33+ — gives false confidence
await Permissions.RequestAsync<Permissions.StorageRead>();
// ✅ Use the specific media permission
await Permissions.RequestAsync<Permissions.Photos>(); // photo access
await Permissions.RequestAsync<Permissions.Media>(); // audio/video
Windows doesn't have runtime permission dialogs for most features. Declare capabilities in Package.appxmanifest instead.
The recommended pattern handles iOS one-shot and Android rationale:
public async Task<PermissionStatus> CheckAndRequestPermissionAsync<T>()
where T : Permissions.BasePermission, new()
{
var status = await Permissions.CheckStatusAsync<T>();
if (status == PermissionStatus.Granted)
return status;
if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.iOS)
return status; // iOS won't show dialog again
if (Permissions.ShouldShowRationale<T>())
{
await Shell.Current.DisplayAlert("Permission needed",
"This feature requires the requested permission.", "OK");
}
return await Permissions.RequestAsync<T>();
}
CheckStatusAsync called before every RequestAsyncOnAppearing or commandsPermissionStatus values handled (Denied, Restricted, Limited)ShouldShowRationale shown before re-requestingPhotos/Media instead of StorageRead/StorageWrite