In Appium, which execute method changes an app permission on Android, and which on iOS?
answer
- two commands, not one API
- package manager on one side
- a bundle decision on the other
- one of the pair is Simulator-only
basics
~20 sOn Android the Android drivers expose mobile: changePermissions, which grants or revokes a permission on an installed package. On Apple platforms the XCUITest driver exposes mobile: setPermission, which writes a decision for a bundle and only works on a Simulator.
solid answer
~40 sThere are two unrelated commands, one per platform. On Android, `appium-android-driver` — the base both the UiAutomator2 and Espresso drivers extend — exposes `mobile: changePermissions`, which grants or revokes a named permission on an installed package through the device's package manager. It runs on emulators and real devices, and `mobile: getPermissions` reads the set back. On Apple platforms the XCUITest driver exposes `mobile: setPermission`, which writes a decision for a bundle identifier, but it is **Simulator-only** and throws on real hardware, as does its reader `mobile: getPermission`. The one Apple permission command that survives on a real device is `mobile: resetPermission`, which clears the decision rather than setting it. Android additionally has a session-wide shortcut, the `appium:autoGrantPermissions` capability.
code
java · 12 linesString platform = (String) driver.getCapabilities().getCapability("platformName");
if ("Android".equalsIgnoreCase(platform)) {
driver.executeScript("mobile: changePermissions", Map.of(
"action", "grant",
"appPackage", "com.vineyard.harvestlog",
"permissions", "android.permission.CAMERA"));
} else {
driver.executeScript("mobile: setPermission", Map.of(
"bundleId", "com.vineyard.harvestlog",
"access", Map.of("camera", "yes")));
}go deeper
Be ready to name both commands and pair each with its platform: mobile: changePermissions on Android, mobile: setPermission on Apple platforms. Getting the pairing backwards is the fastest way to lose the question.
Explain why two commands exist rather than one. The Android drivers write through the device's package manager, while the XCUITest command drives host-side Simulator tooling, which is exactly why it has no real-device story.
Show that you plan around the Simulator-only limit before a suite meets real hardware. Say what your setup step falls back to on a plugged-in iPhone and how it confirms the seed actually took effect.
Own the consequence for the fleet. A precondition that only holds on some device classes is a portability boundary, and it belongs in an explicit, declared contract rather than buried inside a setup helper.
## Why there are two commands and not one A runtime permission is a decision the operating system stores **outside** your application: the app asks, the system draws its own modal, the user answers, and the answer persists until something clears it. Appium's job in this leaf is to write that stored decision **directly**, so a test never has to locate and tap a system dialog it does not own. Both mobile platforms allow that, but they allow it through completely different machinery — so Appium ships **two unrelated execute methods** rather than one portable one, and knowing which name belongs to which platform is the whole of the junior-level answer. On Android the command is `mobile: changePermissions`, declared in **`appium-android-driver`**. That matters: it is not a UiAutomator2-only command. `appium-android-driver` is the base driver that both the UiAutomator2 driver and the Espresso driver extend, so the method is available under either `appium:automationName`. It reaches the device's **package manager** and grants or revokes a named permission on an installed package. It runs on emulators and on real devices alike, at any point during a session, and it can target any installed package rather than only the app under test. On Apple platforms the counterpart is the XCUITest driver's `mobile: setPermission`, which writes a decision for a **bundle identifier** instead of a package name. It is **Simulator-only**: on a real iPhone or iPad it throws, because the facility behind it lives on the host beside the Simulator rather than inside the device. ## The full per-platform surface | Concern | Android (the Android drivers) | Apple (the XCUITest driver) | |---|---|---| | Write a decision | `mobile: changePermissions` | `mobile: setPermission` (Simulator only) | | Read it back | `mobile: getPermissions` (plural) | `mobile: getPermission` (singular) | | Clear the decision | revoke via `mobile: changePermissions` | `mobile: resetPermission` (Simulator **and** real device) | | Blanket grant at install | `appium:autoGrantPermissions` capability | no install-time equivalent | | App is named by | a package name | a bundle identifier | | Permission is named by | a platform permission string | a named service | The plural-versus-singular split in the readers is not a documentation slip. Android's `mobile: getPermissions` answers with the package's permission list; the XCUITest driver's `mobile: getPermission` answers about one named service for one bundle. The shapes differ because the underlying models differ. ## Working the vineyard harvest-log app Take a **vineyard harvest-log app** that photographs every bin arriving at the press house and stamps it with the block it came from, so it wants camera and location access. On an Android session the setup step calls `mobile: changePermissions` with a grant action, the harvest-log package name and the camera permission string, and the app never raises a prompt. On an iOS Simulator the same setup step calls `mobile: setPermission` with the harvest-log bundle identifier and camera set to the granted value. In a test's source the two calls look like siblings. Underneath they share nothing — not the transport, not the identifier, not the vocabulary for the permission itself. ## What each command cannot do - `mobile: setPermission` and `mobile: getPermission` **do not run on real Apple hardware**, so a suite that plans to graduate from Simulators must know this before it does. - `mobile: resetPermission` is the Apple command that does reach a real device — it proxies to WebDriverAgent's `/wda/resetAppAuth` — but it only **clears**, it cannot set a chosen value. - `mobile: changePermissions` cannot conjure a permission the application never declared; it flips a decision on something already in the package's declared set. - The Android command can also work through the device's **app-ops layer** rather than the package manager, for the appop-backed entries the package manager alone will not flip. - Neither write command touches a dialog. Writing the stored decision underneath a prompt that is already on screen is not the same act as answering that prompt. - `appium:autoGrantPermissions` is a **capability**, fixed when the session is created, so it can never express a per-case intent the way an execute method can. ## Choosing between them in a real suite 1. Decide the intent first — this case starts with camera access already granted — and only then pick the command, because the command is platform-specific and the intent is not. 2. Seed while the app is not in the foreground. Changing a permission an already-running app holds can take its process down with it, and a restart mid-case looks exactly like a crash. 3. Read the state back where you can. `mobile: getPermissions` on Android and `mobile: getPermission` on a Simulator both let a setup step assert its own work instead of hoping. 4. Keep the two vocabularies apart in your helper. There is no shared name to key a map on, so any cross-platform layer needs its own permission enum plus two translations. ## The mistakes that survive review The commonest error in an interview is treating the pair as one API with two spellings, and assuming a call that works on a Simulator will work on a plugged-in iPhone. The second commonest is filing `mobile: changePermissions` under the UiAutomator2 driver: it is the **Android base driver's**, which is precisely why an Espresso session gets it too. Say the driver's name as well as the platform's, every time, and the answer holds up.
- Which command reads a permission back on each platform, and how do the two differ?Android's `mobile: getPermissions` is plural: it answers with the package's permission list. The XCUITest driver's `mobile: getPermission` is singular — you name one service for one bundle and get its current state back. Like `mobile: setPermission`, the Apple reader only answers on a Simulator, so a real-device suite has no read-back path at all.
- Can Appium grant a permission on a real iPhone at all?Not to a chosen value. `mobile: setPermission` and `mobile: getPermission` are Simulator-only. On real Apple hardware only `mobile: resetPermission` works — it proxies to WebDriverAgent's `/wda/resetAppAuth` and clears the stored decision, so the system asks again the next time the app needs the resource. You then deal with that prompt rather than pre-empt it.
- Is mobile: changePermissions specific to the UiAutomator2 driver?No. It is declared in `appium-android-driver`, the base driver that both the UiAutomator2 and the Espresso drivers extend, so both inherit it. Only a small gesture-and-window set is declared in the UiAutomator2 repository itself; most of the Android execute-method surface, the permission commands included, lives in that base driver.
saying these in an interview costs you the question
- Assumes one Appium command covers both platforms
- Thinks mobile: setPermission works on a real iPhone
- Calls mobile: changePermissions an XCUITest command
- Believes a permission can only be set by tapping the dialog
- Confuses the plural Android reader with the singular Apple one