Skip to content
Back to skills

Platform Permissions

ASecurity

Use when a feature needs camera, location, photos, notifications, contacts, microphone, Bluetooth, or local network - the per-platform request flow, every denial state, and how to actually test the denied path when the shared test device auto-grants permissions.

  • 109 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsgotestingapi

Works with

  • api

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add makifbaysal/tasktrooper --skill platform-permissions --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Platform Permissions?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Platform Permissions
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/makifbaysal-platform-permissions/badge)](https://www.skillsdirectory.com/skills/makifbaysal-platform-permissions)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: platform-permissions
category: mobile
description: Use when a feature needs camera, location, photos, notifications, contacts, microphone, Bluetooth, or local network - the per-platform request flow, every denial state, and how to actually test the denied path when the shared test device auto-grants permissions.
---
# Platform Permissions

## Overview

A permission request handled only for the happy path (granted) crashes or dead-ends for a meaningful share of real users. Every state needs a designed response, and the denied path is the one app reviewers and store checks hit first.

## iOS

- Every permission needs an `NS*UsageDescription` string in `Info.plist` *before* the request is made — a missing one terminates the app immediately when the request fires, not a graceful denial.
- The system prompt shows **once**. After a denial, there is no re-prompt API: deep-link to Settings with `UIApplication.openSettingsURLString` and explain why, rather than repeatedly calling the request API hoping for a different answer.

## Android

- Check `shouldShowRequestPermissionRationale` to decide whether to show an explanation before requesting, or whether the user already chose "don't ask again" (in which case rationale won't show and you go straight to a Settings deep-link).
- `POST_NOTIFICATIONS` is a runtime permission since API 33 — request it like any other dangerous permission, not assumed granted.
- Prefer the **Photo Picker** over `READ_MEDIA_IMAGES`/`READ_MEDIA_VIDEO` when the feature only needs the user to pick specific media — it needs no permission at all.
- Request coarse location before fine location when both are relevant, and only request what the feature actually uses.
- A local-network permission applies on recent Android versions for apps that discover devices on the LAN — verify the exact permission name against the current platform docs when you're about to use it; don't guess.

## Flutter

- `permission_handler`: check `.isPermanentlyDenied` to distinguish "ask again" from "must deep-link to settings" (`openAppSettings()`).

## Every state needs a response

`granted` · `denied` (show rationale, allow retry) · `restricted` (parental controls/MDM — no retry is possible, say so) · `permanently denied` (deep-link to Settings) — the feature degrades gracefully without the permission in every case; a denial never crashes or silently dead-ends the flow.

## Testing reality in TaskTrooper

The shared Android test device auto-grants permissions (`appium:autoGrantPermissions: true`), so the denied/restricted/permanently-denied paths **cannot** be exercised by requesting on that device — a manual test there will always show "granted" regardless of what you're verifying. Test those paths with a fake permission service injected in a widget/unit test instead (stub it to return denied/restricted/permanently-denied and assert the UI responds correctly), and say explicitly in the closing message that the denied path was verified via a fake, not on-device.

## Common Mistakes

- Requesting a permission with no prior rationale, as a wall of prompts at first launch.
- Missing `NS*UsageDescription` for a permission the code requests.
- Treating "permanently denied" the same as "denied" and calling the request API again (it won't re-prompt).
- Assuming the shared device's auto-grant means the denied path was tested.
- `READ_MEDIA_IMAGES` for a simple "pick one photo" feature instead of the Photo Picker.

## Red Flags

- A permission-gated feature with no denied/restricted/permanently-denied UI at all.
- A closing message claiming "tested denied path" with a device known to auto-grant and no fake-service test in the diff.
- A Settings deep-link with no explanation of why the user is being sent there.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…