flutter-permission-handler-engineering
Skill8 starsChanged 48 days agoMITView on GitHub
Design, implement, review, debug, test, migrate, and secure Flutter runtime-permission flows using `permission_handler`. Use this skill whenever a Flutter task involves camera, microphone, location, background location, photos/media, contacts, calendars, Bluetooth/Nearby Devices, notifications, tracking, sensors, Android special access, permission statuses, rationale/settings recovery, Android/iOS permission configuration, permission-related upgrades, or privacy-preserving alternatives—even when the user only asks why a permission prompt fails or whether an app should request a permission.
In this repository70 other files it gives its agents.
- camerawesome-flutterSkill
- dart-args-production-cliSkill
- dart-flutter-equatable-engineeringSkill
- dart-flutter-ffi-systems-engineeringSkill
- dart-metaSkill
- document-camera-frameSkill
- document-scan-flutterSkill
- figma-to-flutter-expertSkill
- flutter-animations-production-engineeringSkill
- flutter-app-hardening-reverse-engineeringSkill
- flutter-app-icon-engineeringSkill
- flutter-application-security-engineeringSkill
- flutter-app-links-deep-link-engineeringSkill
- flutter-cachingSkill
- flutter-concurrency-memory-performanceSkill
- flutter-confetti-engineeringSkill
- flutter-dart-package-engineeringSkill
- flutter-design-system-from-design-mdSkill
- flutter-dio-cache-interceptor-engineeringSkill
- flutter-dio-engineeringSkill
- flutter-doc-scannerSkill
- flutter-drift-persistence-engineeringSkill
- flutter-expert-tipsSkill
- flutter-firebase-analyticsSkill
- flutter-firebase-core-engineeringSkill
- flutter-firebase-messagingSkill
- flutter-get-it-injectable-dependency-injectionSkill
- flutter-go-router-engineeringSkill
- flutter-hive-persistence-engineeringSkill
- flutter-image-performanceSkill
- flutter-image-picker-production-engineeringSkill
- flutter-lints-static-analysis-engineeringSkill
- flutter-local-notifications-production-engineeringSkill
- flutter-memory-leak-engineeringSkill
- flutter-mobile-developmentSkill
- flutter-motion-engineeringSkill
- flutter-multi-environmentSkill
- flutter-native-splash-engineeringSkill
- flutter-package-plugin-selectionSkill
- flutter-path-provider-production-storageSkill
- flutter-performance-jank-optimizationSkill
- flutter-pinputSkill
- flutter-production-build-releaseSkill
- flutter-production-engineeringSkill
- flutter-production-loggingSkill
- flutter-pro-image-editor-engineeringSkill
- flutter-secure-storage-security-engineeringSkill
- flutter-sentry-engineeringSkill
- flutter-share-plus-engineeringSkill
- flutter-skeletonizer-engineeringSkill
- flutter-squadron-concurrency-engineeringSkill
- flutter-supabase-engineeringSkill
- flutter-svg-engineeringSkill
- flutter-ui-performance-engineeringSkill
- flutter-url-launcher-engineeringSkill
- flutter-video-player-production-engineeringSkill
- flutter-webview-production-engineeringSkill
- freezed-production-engineeringSkill
- html-to-flutterSkill
- hydrated-blocSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
49 rules. About 0 are common, 35 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈35
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Treat runtime permission handling as privacy-sensitive product behavior, not as a mechanical plugin call.
- Very specific: line 13
Start from the user capability, not from Permission.*.
- Distinctive: line 14
Ask whether runtime permission is required at all.
- Distinctive: line 15
Prefer picker, intent, manual input, approximate scope, foreground scope, or add-only access when it removes broader permission.
- Distinctive: line 16
Never request permissions “just in case” or batch unrelated sensitive permissions at startup.
- Very specific: line 17
Never request/check permission from build() and never poll permission state.
- Very specific: line 18
Treat the OS as authorization source of truth.
- Very specific: line 20
Treat limited as partial access, restricted as device/account policy, and provisional as notification-specific.
- Distinctive: line 21
Do not loop permission requests after denial.
- Distinctive: line 22
Never open system settings automatically.
- Very specific: line 26
Keep Permission, PermissionStatus, and BuildContext out of domain entities/services.
- Distinctive: line 27
Keep Android/iOS static declarations minimal and aligned with product behavior.
- Distinctive: line 29
Never describe permission routing as backend authorization or a security boundary.
- Distinctive: line 36
When behavior is uncertain, prefer the installed release and matching platform implementation over old tutorials or repository main.
- Distinctive: line 38
Before editing permission behavior, inspect:
- Very specific: line 55
Search for high-risk patterns: .request() in main/splash/build/initState, Permission.storage, locationAlways, broad Contacts/Photos access, …
- Distinctive: line 56
Do not refactor until each permission maps to a real feature.
- Distinctive: line 59
Write the behavior first: “User scans a QR code”, “records voice”, “selects one photo”, “enables reminders”.
- Distinctive: line 61
Ask whether the feature can use no permission, a system picker, manual input, an external intent, approximate location, foreground-only …
- Distinctive: line 63
Document only relevant combinations such as Android ≤32/33/34+, target-SDK behavior, iOS <17/17+/18+, Web, and Windows.
- Distinctive: line 65
Add only the manifest/privacy declarations required by the feature.
- Distinctive: line 79
Do not re-request states that cannot or need not produce a useful prompt: granted, useful limited access, restricted, or permanently denied.
- Distinctive: line 87
After authorization, verify what the feature still needs:
- Very specific: line 94
Do not show permission recovery UI for a hardware/service/configuration failure.
- Distinctive: line 101
Never auto-open Settings or create a settings loop.
- Distinctive: line 113
Before broad access, evaluate:
- Very specific: line 127
Before Android changes, read references/02-android-permissions.md and reason from:
- Distinctive: line 135
Prefer Photo Picker when broad media-library access is unnecessary.
- Distinctive: line 140
Treat all-files access, overlay, exact alarms, install packages, and battery-optimization exemption as special app access, not ordinary …
- Distinctive: line 142
Do not copy unreleased Android 17/local-network APIs into stable 12.x projects.
- Very specific: line 144
Before iOS changes, read references/03-apple-web-desktop-and-capabilities.md and reason from:
- Distinctive: line 151
Do not mix CocoaPods and SPM configuration instructions.
- Very specific: line 152
Use calendarWriteOnly vs calendarFullAccess deliberately on iOS 17+.
- Very specific: line 153
Treat Photos/Contacts limited as usable partial authorization when the feature supports it.
- Distinctive: line 174
Do not build a large permission framework for a trivial one-permission app unless it adds real policy/testability value.
- Very specific: line 177
If launching Settings, track that a relevant settings journey is active and re-check on AppLifecycleState.resumed.
- Very specific: line 183
Read references/04-architecture-testing-debugging-and-migration.md for full coverage.
- Distinctive: line 187
Do not use a device with unknown long-lived permission history as the only clean-user test.
- Distinctive: line 189
When a request does nothing or always returns denied, inspect in this order:
- Distinctive: line 203
Never broaden permission scope merely to make a prompt appear.
- Distinctive: line 206
Do not upgrade and only fix compile errors until green.
- Distinctive: line 232
When implementing/reviewing permissions, report:
- Very specific: line 250
Do not report “permission handled” when only .request() was added.
- Distinctive: line 252
Do not approve release until relevant checks pass:
- Distinctive: line 253
every permission maps to a real feature and minimum privilege is used.
- Distinctive: line 255
no unnecessary startup requests exist.
- Distinctive: line 260
all relevant statuses are handled distinctly and partial access works where possible.
- Distinctive: line 264
no permission work occurs in rebuild hot paths.
- Distinctive: line 268
If any answer is unknown, treat the permission implementation as incomplete.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Flutter Permission Handler Engineering
Mission
Treat runtime permission handling as privacy-sensitive product behavior, not as a mechanical plugin call. Prioritize: user privacy → correct platform behavior → least privilege → feature correctness → user trust → graceful degradation → maintainability → testability → performance → developer convenience. Central invariant:
Request the least access necessary for one understandable user action, interpret the exact platform state, and keep unrelated application functionality useful when the user says no.
Operating Rules
- Start from the user capability, not from
Permission.*. - Ask whether runtime permission is required at all.
- Prefer picker, intent, manual input, approximate scope, foreground scope, or add-only access when it removes broader permission.
- Never request permissions “just in case” or batch unrelated sensitive permissions at startup.
- Never request/check permission from
build()and never poll permission state. - Treat the OS as authorization source of truth; do not persist
granted = trueas authority. - Handle
denied,permanentlyDenied,restricted,limited, andprovisionaldeliberately. - Treat
limitedas partial access,restrictedas device/account policy, andprovisionalas notification-specific. - Do not loop permission requests after denial.
- Never open system settings automatically; offer it through explicit user action and re-check after resume.
- Distinguish permission from service state, hardware availability, and feature initialization.
- Initialize camera, recorder, scanner, Bluetooth scan, location stream, or similar resources only after authorization.
- Serialize competing permission prompts in complex applications.
- Keep
Permission,PermissionStatus, andBuildContextout of domain entities/services. - Keep Android/iOS static declarations minimal and aligned with product behavior.
- Re-test when target SDK, OS baseline, package version, or Apple privacy configuration changes.
- Never describe permission routing as backend authorization or a security boundary.
Reference Routing
references/01-foundations-status-and-requests.md— package setup, responsibility boundaries, statuses, rationale, timing, multiple requests, and coordination.references/02-android-permissions.md— Android API levels, manifest, media/storage, notifications, Bluetooth, location/background location, Nearby Wi-Fi, and special app access.references/03-apple-web-desktop-and-capabilities.md— iOS configuration, CocoaPods/SPM, limited Photos/Contacts, location accuracy, notifications, ATT, calendar, Web/Windows differences, service/capability checks, settings return, and feature flows.references/04-architecture-testing-debugging-and-migration.md— service boundaries, Bloc/Cubit/DI, revocation, errors, performance, observability, testing, debugging, and migration.references/05-antipatterns-workflows-and-checklists.md— full anti-pattern catalog, implementation/review workflows, platform/privacy checklists, and production readiness. When behavior is uncertain, prefer the installed release and matching platform implementation over old tutorials or repositorymain.
Repository Inspection
Before editing permission behavior, inspect:
pubspec.yaml + lockfile
Flutter/Dart versions
permission_handler + platform package versions
Android compileSdk / targetSdk / minSdk
AndroidManifest.xml permissions and maxSdkVersion bounds
iOS dependency manager: CocoaPods or SPM
Info.plist usage descriptions
Podfile macros or SPM permission configuration
Apple entitlements
all Permission.* / .status / .request / .isGranted usages
openAppSettings() and lifecycle-resume flows
service-status checks
feature-specific hardware initialization
permission testsSearch for high-risk patterns: .request() in main/splash/build/initState, Permission.storage, locationAlways, broad Contacts/Photos access, special app access, automatic openAppSettings(), concurrent request Futures, persisted grant booleans, or raw PermissionStatus in domain models.
Do not refactor until each permission maps to a real feature.
Decision Workflow
1. Name the user capability
Write the behavior first: “User scans a QR code”, “records voice”, “selects one photo”, “enables reminders”. Do not begin with “the app needs camera/location”.
2. Challenge the permission requirement
Ask whether the feature can use no permission, a system picker, manual input, an external intent, approximate location, foreground-only access, or add-only access. Prefer the narrower design when it satisfies the product.
3. Identify platform/version scope
Document only relevant combinations such as Android ≤32/33/34+, target-SDK behavior, iOS <17/17+/18+, Web, and Windows. Do not invent one universal prompt model.
4. Configure static declarations
Add only the manifest/privacy declarations required by the feature. On iOS, identify CocoaPods vs SPM before changing permission configuration.
5. Request at understandable user intent
Good:
Tap Scan QR → optional rationale → request camera → initialize cameraBad:
First frame → camera + contacts + location + notifications6. Check current status
final status = await Permission.camera.status;Do not re-request states that cannot or need not produce a useful prompt: granted, useful limited access, restricted, or permanently denied. Handle provisional according to notification policy.
7. Decide rationale
On Android, shouldShowRequestRationale is one signal, not a state machine. Never infer permanent denial from it alone. Explain what the feature does, why access is needed, and what remains usable if declined. Do not imitate the OS sheet or pressure the user.
8. Request only the immediate permission set
Group only permissions required for the same action. Video with audio may justify camera + microphone; still photography does not. Sequence mandatory and optional capabilities separately.
9. Map exact result into application state
Preserve at least: granted, limited, provisional, denied, permanently denied, restricted. Do not reduce immediately to Boolean.
10. Check service and capability
After authorization, verify what the feature still needs:
location permission → Location Services → actual location result
Bluetooth permission → adapter enabled → scan/connect capability
camera permission → camera exists → controller initializes
notification permission → token/backend/channel configurationDo not show permission recovery UI for a hardware/service/configuration failure.
11. Degrade gracefully
Disable only the dependent capability unless the product truly cannot function without it. Examples: Contacts denied → manual entry; notifications denied → app remains usable; Photos limited → use accessible subset.
12. Recover through Settings deliberately
explain limitation → user taps Open Settings → app resumes → re-check relevant permission → update feature stateNever auto-open Settings or create a settings loop.
PermissionStatus Policy
| Status | Default response |
granted | Continue, then check service/hardware/resource capability |
limited | Continue if partial access satisfies the feature; otherwise explain why broader access is needed |
provisional | Notification-specific noninterruptive authorization |
denied | Respect; request again only after renewed user intent and while requestable |
permanentlyDenied | Explain and offer explicit Settings action |
restricted | Explain device/account policy; do not loop request/settings |
Remember that denied may also represent not-yet-requested state depending on platform/history. |
Privacy-Preserving Alternatives Gate
Before broad access, evaluate:
| Need | Prefer |
| One/few photos | System photo picker |
| One document | System document picker |
| One phone/email/contact value | Manual input or system selection |
| Dial or compose SMS | tel: / sms: intent |
| App-private files | App-specific storage |
| Save shared media on modern Android | Platform media API without broad read where supported |
| Approximate nearby experience | Coarse/approximate location |
| Foreground-only location | locationWhenInUse |
| Add calendar event only on modern iOS | calendarWriteOnly |
| Broad access requires an explicit product reason. |
Android Gate
Before Android changes, read references/02-android-permissions.md and reason from:
OS API level + targetSdkVersion + manifest + user history + installed package versionKey rules:
- Stable 12.0.x documentation requires compile SDK 35; verify the repository before changing build config.
- Compile SDK and target SDK are different decisions.
Permission.storageis not a modern Android 13+ media solution.- Prefer Photo Picker when broad media-library access is unnecessary.
- Android 13+ notifications use
POST_NOTIFICATIONS. - Android 12+ Bluetooth uses scan/connect/advertise according to operation; do not add location unless truly required.
- Handle Android 14 selected media as
limitedwhere supported by the installed implementation. - Request foreground location before background location; Android 11+ background access may be settings-mediated.
- Treat all-files access, overlay, exact alarms, install packages, and battery-optimization exemption as special app access, not ordinary dangerous permissions.
- Re-test affected flows after target-SDK upgrades. Do not copy unreleased Android 17/local-network APIs into stable 12.x projects.
Apple Gate
Before iOS changes, read references/03-apple-web-desktop-and-capabilities.md and reason from:
permission API + Info.plist + CocoaPods macro OR SPM config + entitlement + OS authorization stateKey rules:
- Missing privacy declarations can terminate the app when protected APIs are accessed.
- Enable only permission strategies actually used.
- Do not mix CocoaPods and SPM configuration instructions.
- Use
calendarWriteOnlyvscalendarFullAccessdeliberately on iOS 17+; do not introduce deprecatedPermission.calendar. - Treat Photos/Contacts
limitedas usable partial authorization when the feature supports it. - Generic location permission does not encode reduced vs full accuracy.
- Notification authorization does not prove APNs/FCM/token/backend delivery.
- ATT is not generic analytics consent.
- Siri/critical-alert entitlements are separate from usage-description text.
Web / Windows Gate
Do not assume mobile semantics. Web support is narrower, browser secure-context/origin/user-gesture rules matter, and openAppSettings() is not a mobile-style recovery path. On Windows, generic plugin permission checks do not represent the same runtime-privacy model as Android/iOS; use feature-specific Windows capability/privacy APIs when actual authorization matters. Verify installed support before asserting macOS behavior.
Architecture
For nontrivial applications, prefer:
UI
↓
Bloc / Cubit / Riverpod / coordinator
↓
AppPermissionService
↓
permission_handler
↓
OSThe permission abstraction should map plugin states into application states, centralize platform/version policy where useful, remain free of BuildContext, and return state rather than showing dialogs/navigation. Presentation owns rationale UI, settings CTA, navigation, and degradation. Use an application-scoped request coordinator if multiple features can trigger OS prompts concurrently.
Do not build a large permission framework for a trivial one-permission app unless it adds real policy/testability value.
Revocation and Lifecycle
Assume permission can change outside the app through Settings, one-time permission expiry, Android auto-reset, device policy, or limited Photos/Contacts selection changes. Re-check only at meaningful boundaries: immediately before protected capability use when stale authorization matters, after relevant Settings return, or when re-entering an active feature whose permission may have changed. Do not poll.
If launching Settings, track that a relevant settings journey is active and re-check on AppLifecycleState.resumed.
Performance Rules
Permission checks are rarely the primary bottleneck. Optimize correctness first: no status Future recreated on every build, no periodic polling, no duplicate simultaneous prompts, and no heavy camera/recorder/scanner/location initialization before authorization.
Security and Privacy Rules
Permission grant is consent to one OS capability, not backend authorization. Minimize requested scope and data collected after grant; avoid protected resource contents in logs/analytics; preserve user choice; make optional denial survivable. Reject coercive rationale, repeated prompts, fake system dialogs, or blocking unrelated functionality merely to raise consent rate.
Testing Gate
Read references/04-architecture-testing-debugging-and-migration.md for full coverage.
Unit-test application policy with fakes for granted, denied, permanently denied, restricted, limited when relevant, and provisional when relevant.
Widget-test rationale/recovery UI, one request per explicit interaction, settings CTA, partial-access UX, and restricted UX.
Real platform tests should cover clean install, first prompt, grant, deny, repeated/permanent denial, settings recovery, external revocation, permission granted + service disabled, lifecycle resume, relevant Android API boundaries, and relevant Apple partial/restricted/accuracy states.
Do not use a device with unknown long-lived permission history as the only clean-user test.
Debugging Workflow
When a request does nothing or always returns denied, inspect in this order:
- installed package version;
- target platform support;
- OS/API support for the permission;
- Android manifest declaration;
- Android target-SDK behavior;
- iOS Info.plist key;
- CocoaPods macro or SPM configuration;
- required entitlement;
- exact current status;
- foreground Activity/app availability;
- whether it is special app access rather than a normal prompt;
- whether the actual failure is service/hardware/configuration rather than authorization.
Typical diagnoses: Android 13+
Permission.storagedenial is expected; iOS prompt failure may be prior permanent denial or missing static config; location can be granted while Location Services is disabled; settings recovery may fail because the user changed nothing or the platform does not support opening app settings. Never broaden permission scope merely to make a prompt appear.
Migration Workflow
Treat package, OS, and target-SDK changes as behavioral migrations. Before upgrading: record package/platform-package versions; read changelog and platform changes; verify Flutter/Dart minimums and Android compile SDK; review target-SDK behavior, manifest, Info.plist, CocoaPods/SPM config, entitlements, deprecated/new constants, and status semantics; then run clean-install, denied, settings-return, Android API-boundary, and Apple partial-state tests. Do not upgrade and only fix compile errors until green.
Anti-Patterns
Reject without explicit justification:
- request-all-at-startup flows;
- permission work from
build(); - unconditional requests from every screen
initState; - request loops after denial;
- treating denied/permanent or limited/denied identically;
- automatic Settings navigation or reopen loops;
- blocking whole app for optional capability;
- background location before foreground;
- microphone for still photography;
- full Contacts access for one value;
- legacy Android storage for modern media;
- unconditional location for Bluetooth;
- missing Android 13 notification permission;
- missing Apple usage descriptions or copied obsolete Podfile macros;
- permission checks every rebuild or continuous polling;
- persisted grant booleans as authority;
- resource initialization before authorization;
PermissionStatusin domain entities orBuildContextin permission services;- concurrent unrelated request Futures;
- conflating permission with service/hardware/push delivery;
- fake system prompts or coercive gates.
See
references/05-antipatterns-workflows-and-checklists.mdfor the full supplied catalog and corrected patterns.
Reporting Format
When implementing/reviewing permissions, report:
Feature capability
Permission actually required?
Privacy-preserving alternative considered
Target platforms / OS-version boundaries
Static platform declarations
Status/request state machine
Rationale and timing
Limited/restricted/permanent behavior
Settings recovery
Service/hardware checks
Architecture owner
Concurrency coordination
Tests performed / required
Version-sensitive assumptions
Remaining risksDo not report “permission handled” when only .request() was added.
Production Gate
Do not approve release until relevant checks pass:
- every permission maps to a real feature and minimum privilege is used;
- picker/intent/manual alternatives were evaluated;
- no unnecessary startup requests exist;
- Android manifest is minimal/version-aware, compile SDK requirement is satisfied, and target-SDK behavior is reviewed;
- modern Android media/notification/Bluetooth/location behavior is correct and background location is justified/sequenced;
- Apple usage descriptions are truthful/complete, CocoaPods/SPM config matches the project, and required entitlements exist;
- deprecated permission APIs are removed where applicable;
- all relevant statuses are handled distinctly and partial access works where possible;
- service/hardware state is checked separately;
- Settings is user-triggered and rechecked on return;
- simultaneous prompts are coordinated;
- no permission work occurs in rebuild hot paths;
- sensitive resources initialize only after authorization;
- clean-install, denial-state, and relevant OS/API-boundary tests pass;
- current installed package behavior has been verified. If any answer is unknown, treat the permission implementation as incomplete.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

