What this tool is for
settings-permissions edits the platform's permission store directly - the iOS simulator's TCC database, or Android's package-manager permission flags. It replaces the manual Settings → Privacy dance during test setup: pre-authorize a service so the app never has to ask, deny it up front to test the refusal path, or reset it so the first-run dialog appears again on the next launch.
It is a test-setup / out-of-band tool, not a general permissions toggle. The default way to change a permission is still through the app - this tool is the exception for the cases the app can't reach.
When to use it - and when NOT to
Decide with this order. The first matching row wins.
Rule of thumb: if a human tester could flip it inside the app, do that. Reach for settings-permissions only for a change a human would otherwise make in the system Settings app.
Supported permissions & platform coverage
One abstract permission can map to several concrete Android permissions; which ones actually exist depends on the app's manifest and the device's API level (e.g. READ_MEDIA_* on API 33+ vs READ_EXTERNAL_STORAGE below it).
Actions
grant- pre-authorize the permission. RequiresbundleId.deny- refuse it. RequiresbundleId. Use to test the app's "permission denied" path.reset- return to the not-yet-asked state so the dialog reappears on next use. Always per-app (bundleIdrequired):- iOS: removes that app's TCC row. A device-wide reset (no bundleId) is not offered - on recent iOS runtimes it reports success but leaves existing per-app grants untouched, so it would report a change that never happened.
- Android: revokes the grant, then best-effort clears the user-set/user-fixed flags (flag-clearing first appears in Android 13 / API 33; the revoke is what counts toward success). Below API 33 (i.e. API 23-32, everywhere a user-fixed state can exist) flag-clearing is unavailable, so a
resetthere revokes the grant but cannot clear a "don't ask again" (user-fixed) state - the dialog may stay suppressed on those older devices.
Parameters
udid- target fromlist-devices(iOS simulator UDID, or Android serial). Seeargent-ios-simulator-setup/argent-android-emulator-setupto get one.action-grant|deny|reset.permission- one of the 11 names above.bundleId- iOS bundle id or Android package name. Required for every action.
Platform behavior
iOS simulator only. Edits the simulator's TCC store - always per-app (bundleId required). There is no host-side TCC switch on a physical iPhone, so this tool does not apply to real iOS devices. The simulator must be booted first (boot-device) - otherwise the tool fails with a "current state: Shutdown" error and surfaces the boot hint.
Android emulator and physical device. Changes the app's android.permission.* runtime permissions over adb (and, for reset, best-effort clears the user-set/user-fixed flags - the revoke is what decides success; flag-clearing needs Android 13 / API 33+). Requirements:
- The app must be installed - the tool probes for the package first and errors clearly if it is missing (a transport/timeout failure surfaces adb's real cause, not a false "not installed").
- The app must declare the permission in its manifest. The package manager rejects any mapped permission the manifest doesn't request; those come back in the result's
skippedlist. The action succeeds if at least one mapped permission sticks, and errors only if all of them were rejected.
Gotchas
- Changing a permission can terminate a running app (system behavior on both platforms). Prefer setting permissions before
launch-app; if you change one while the app is running,restart-appafterward. - Reset is per-app on both platforms - pass
bundleId; there is no reliable device-wide reset. - A partial Android result is normal.
appliedlists what actually changed;skippedlists mapped permissions the package manager rejected (usually not in the manifest, or gated by API level). Both together tell you what happened. - A pre-launch
denysuppresses the prompt on iOS only. On iOS a TCC denial answers the app's request, so no dialog appears. On Android adenyclears the grant but sets no "user-fixed" flag, so the app's next request still shows the system dialog - a pre-launchdenythere tests the revoked state, not a suppressed prompt. cameraon iOS may be rejected by a simulator runtime that doesn't model the service (it varies by simruntime, not by the installed Xcode - a runtime can acceptcameraeven when the platform's own service list omits it). A rejection surfaces as a generic CoreSimulator error, so acamerafailure (unless it's the shutdown-simulator case, which gets the boot hint instead) is reported with a hint about the runtime's supported services.grant locationneeds the app installed first (iOS). Location authorization isn't stored in TCC and isn't applied to a bundle id until the app exists, so a pre-installgrant location/grant location-alwaysrecords nothing. On a local simulator the tool checks install state and errors clearly instead of reporting a false success; on a remote simulator it cannot probe install state, so a pre-install grant there reports success while recording nothing - make sure the app is installed before granting location remotely. (TCC-backed services likecamera/photoscan be granted before install; they persist and apply on install.)
Result
Returns { action, permission, bundleId, applied, skipped? }:
applied- the platform-level services/permissions actually changed (the TCC service(s) on iOS; theandroid.permission.*names on Android).skipped- Android only, present when some mapped permissions were rejected but others succeeded.
The call fails when nothing could be applied - read the error; it names the reason: an unsupported permission for the platform (notifications on iOS, reminders on Android), the app not installed (including a pre-install grant location on iOS), a shutdown simulator (iOS), or every mapped permission being rejected (usually a missing manifest entry). A non-shutdown camera failure additionally hints about the simulator runtime's supported services (a shutdown-simulator failure gets the boot hint instead).
Examples
Pre-grant the camera before launching, so the app never prompts:
Test the denied path - refuse location, then launch and observe the fallback:
Reset notifications on Android so the first-run prompt appears again next launch:
Grant always-on location on Android (fans out to background + foreground automatically):

