AgentStack
SKILL verified MIT Self-run

Maui Permissions

skill-davidortinau-maui-skills-maui-permissions · by davidortinau

>

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add skill-davidortinau-maui-skills-maui-permissions

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Maui Permissions? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

.NET MAUI Permissions — Gotchas & Best Practices

Critical Anti-Patterns

1. Requesting without checking first

// ❌ Shows prompt even if already granted
var status = await Permissions.RequestAsync();

// ✅ Check first — avoids unnecessary prompts
var status = await Permissions.CheckStatusAsync();
if (status != PermissionStatus.Granted)
    status = await Permissions.RequestAsync();

2. Calling permissions in a constructor

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().Result;
}

// ✅ Use OnAppearing, a command, or async initialization
protected override async void OnAppearing()
{
    await CheckAndRequestPermissionAsync();
}

3. Ignoring Denied and Restricted status

// ❌ 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;
}

Platform Pitfalls

⚠️ iOS: One-shot permission dialog

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.

⚠️ Android: ShouldShowRationale timing

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())
{
    await Shell.Current.DisplayAlert("Permission needed",
        "Camera access is required to scan barcodes.", "OK");
}
status = await Permissions.RequestAsync();

⚠️ Android API 33+: StorageRead/StorageWrite are dead

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();

// ✅ Use the specific media permission
await Permissions.RequestAsync();       // photo access
await Permissions.RequestAsync();         // audio/video

⚠️ Windows: Most permissions always return Granted

Windows doesn't have runtime permission dialogs for most features. Declare capabilities in Package.appxmanifest instead.

Always-Check-Before-Request Pattern

The recommended pattern handles iOS one-shot and Android rationale:

public async Task CheckAndRequestPermissionAsync()
    where T : Permissions.BasePermission, new()
{
    var status = await Permissions.CheckStatusAsync();
    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())
    {
        await Shell.Current.DisplayAlert("Permission needed",
            "This feature requires the requested permission.", "OK");
    }

    return await Permissions.RequestAsync();
}

Checklist

  • [ ] CheckStatusAsync called before every RequestAsync
  • [ ] No permission calls in constructors — use OnAppearing or commands
  • [ ] All PermissionStatus values handled (Denied, Restricted, Limited)
  • [ ] Android: ShouldShowRationale shown before re-requesting
  • [ ] iOS: Settings navigation provided for denied permissions
  • [ ] Android API 33+: using Photos/Media instead of StorageRead/StorageWrite
  • [ ] Manifest/plist declarations match runtime permission requests

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.