DevTools
How to catch new app permissions from plugins in Flutter builds
Pro Reference for permission_guard: every variable, option and package it generates. Command: archipelago generate permission_guard
Generate Permission Guard, learn why scanning the built artifact finds permissions that source diffing misses, accept a baseline, and add it to CI.
What you'll learn
- Generating the Permission Guard devtool
- Seeing why a scan of the built artifact catches what source diffing misses
- Accepting a permission baseline and running checks locally
- Adding the check to CI
Prerequisites
- An existing Archipelago monorepo (see Monorepo Scaffolding)
monorepo_toolkitalready generated, because Permission Guard registers a command in it- A Pro or Enterprise subscription
apkanalyzerfrom the Android SDK command-line tools for Android checks
Step 1: Generate Permission Guard
New Pro projects already include this brick. Run it on an older project:
archipelago generate permission_guardThe prompts are:
- appName: your app name, for example
MyApp - isForMonorepo: leave this as
true
Or use a config file:
{
"appName": "MyApp",
"isForMonorepo": true
}archipelago generate permission_guard --config permission_guard_config.jsonStep 2: Understand the Generated Structure
devtools/scripts/permission_guard/
└── lib/src/
├── commands/ # android, ios, update-baseline
├── models/
└── services/
.permissionguard.yaml # Config at the workspace root
permission_baseline/
├── android.txt # Empty on purpose
└── ios.txt # Empty on purposeThe hook registers the permission-guard command in the toolkit.
The baselines start empty. The first real build fails and prints the permissions it found. That forces you to review and accept the list.
Step 3: Know Why It Scans the Built Artifact
A pub package can add permissions without touching your AndroidManifest.xml or Info.plist. It can ship a library with its own manifest. Source diffing misses those. Permission Guard reads the permissions declared in the built APK or IPA. That is the merged list that stores and devices see.
Step 4: Configure
.permissionguard.yaml holds the policy:
fail_on_new: true
warn_on_removed: false
android_baseline_path: permission_baseline/android.txt
ios_baseline_path: permission_baseline/ios.txtStep 5: Build, Then Accept the Baseline
Build an artifact first:
flutter build apk --flavor production
flutter build ipa --flavor production # macOS and Xcode onlyRun the first check. It fails and lists the permissions. Review them, then accept:
dart run monorepo_toolkit permission-guard update-baseline \
--platform android \
--artifact build/app/outputs/flutter-apk/app-production-release.apk
dart run monorepo_toolkit permission-guard update-baseline \
--platform ios \
--artifact build/ios/ipa/MyApp.ipaCommit the two baseline files.
Step 6: Run a Check Locally
dart run monorepo_toolkit permission-guard android \
--apk build/app/outputs/flutter-apk/app-production-release.apk
dart run monorepo_toolkit permission-guard ios \
--ipa build/ios/ipa/MyApp.ipaA match exits 0. A new permission prints a diff and exits with an error. Android App Bundles are not covered, because apkanalyzer reads APKs only.
Step 7: Approve New Permissions
When you add a dependency that needs a permission on purpose, run update-baseline again. Commit the baseline change with the dependency change. Each permission change becomes a reviewed commit.
Step 8: Add to CI
The hook does not edit your workflows. Add the steps yourself, after the build step:
- name: Check Android permissions
run: |
dart run monorepo_toolkit permission-guard android \
--apk apps/<app>/build/app/outputs/flutter-apk/app-production-release.apk- name: Check iOS permissions
run: |
dart run monorepo_toolkit permission-guard ios \
--ipa apps/<app>/build/ios/ipa/<app>.ipaUntil you commit the baselines, the first CI run fails. That is expected.
Common Customizations
| Goal | What to do |
|---|---|
| Check several flavors | Run the guard once per artifact |
| Allow removals without a warning | Keep warn_on_removed: false |
| Move the baselines | Change android_baseline_path and ios_baseline_path |
| Check iOS in CI | Use a macOS job |
Next Steps
- Set up push notifications, which adds permissions to baseline
- Configure monitoring, because infrastructure SDKs can add permissions