skip to content

In Appium, which command sets the device location on Android, and which one on iOS?

level: juniorimportance: should knowfreq 60%

answer

  1. two platforms, two different names
  2. Android says geolocation, Apple says simulated
  3. declared in appium-android-driver, not UiAutomator2
  4. setGeolocation versus setSimulatedLocation

basics

~10 s

Appium has no single location command. The Android drivers answer mobile: setGeolocation, while the Apple XCUITest driver answers mobile: setSimulatedLocation. Both are execute methods carrying latitude and longitude, posted to the session's execute/sync endpoint.

solid answer

~40 s

There is no cross-platform Appium command for this. On Android the execute method is `mobile: setGeolocation`, declared by `appium-android-driver` and inherited by both the UiAutomator2 and Espresso drivers; you pass `latitude` and `longitude` and the driver applies a mock position to the device. On Apple platforms the XCUITest driver declares `mobile: setSimulatedLocation` instead — the same two coordinates, a different name, a different mechanism. Both travel identically: a `POST /session/:sessionId/execute/sync` carrying the `mobile:` name plus one parameter map, so only the command string and the owning driver change. Each family has a read-back and a clear twin — `mobile: getGeolocation` and `mobile: resetGeolocation` on Android, `mobile: getSimulatedLocation` and `mobile: resetSimulatedLocation` on Apple platforms.

code

java · 19 lines
java
import io.appium.java_client.AppiumDriver;
import java.util.Map;

final class PoolFinderLocation {

    static void setLocation(AppiumDriver driver, String platformName, double lat, double lon) {
        String command = "android".equalsIgnoreCase(platformName)
                ? "mobile: setGeolocation"
                : "mobile: setSimulatedLocation";
        driver.executeScript(command, Map.of("latitude", lat, "longitude", lon));
    }

    static void clearLocation(AppiumDriver driver, String platformName) {
        String command = "android".equalsIgnoreCase(platformName)
                ? "mobile: resetGeolocation"
                : "mobile: resetSimulatedLocation";
        driver.executeScript(command, Map.of());
    }
}

go deeper

for a junior

Be ready to name both commands and say which platform each belongs to: mobile: setGeolocation on Android, mobile: setSimulatedLocation on Apple platforms. Naming only one is the answer interviewers hear most often.

for a middle

Explain that these are execute methods posted to execute/sync with a single parameter map, and that the Android one is declared by the base Android driver and inherited by both UiAutomator2 and Espresso.

for a senior

Show how you keep the divergence inside one adapter and how teardown clears the override, so a failed case cannot leave a shared device pinned to a test position.

for a principal

Own the argument that per-platform command names belong behind one narrow interface in the framework, and be able to price the drift that follows when they leak into page objects across a mixed fleet.

## Why there are two commands, not one Most of what a WebDriver test does is platform-neutral: finding an element, clicking it, sending keys and driving the W3C Actions API all mean the same thing wherever the session runs. Telling the device where it is does not work that way. Location is a platform service, and Appium exposes it through each driver's own **execute method** rather than through one shared endpoint, so the Android name and the Apple name are genuinely different strings owned by genuinely different repositories. On Android the command is `mobile: setGeolocation`. It is not declared by the UiAutomator2 driver — it lives in `appium-android-driver`, the base driver that both the UiAutomator2 driver and the Espresso driver extend, so both inherit it through the same execute-method map. On Apple platforms the command is `mobile: setSimulatedLocation`, declared by the XCUITest driver itself. Nothing aliases one to the other, and there is no capability that makes a single name work on both. ## How the call travels An execute method is not a new HTTP route. Your client sends a `POST /session/:sessionId/execute/sync` whose body carries the `mobile:` name as the script and exactly one parameter map as the argument. In a language client that is a plain `executeScript` call, and the shape is worth memorising: - the script string is the full command name, including the `mobile: ` prefix; - the single argument is a map of named parameters, never a positional list; - the driver, not the server core, decides which keys that map accepts; - an unknown `mobile:` name fails inside the driver, so a typo surfaces as an execute-method error rather than a missing route. Because the transport is identical on both platforms, the only thing your code has to branch on is the command string and the driver that owns it. ## The two families side by side | Concern | Android drivers | Apple XCUITest driver | |---|---|---| | Set a position | `mobile: setGeolocation` | `mobile: setSimulatedLocation` | | Read it back | `mobile: getGeolocation` | `mobile: getSimulatedLocation` | | Clear the override | `mobile: resetGeolocation` | `mobile: resetSimulatedLocation` | | Declared in | `appium-android-driver`, inherited by UiAutomator2 and Espresso | the XCUITest driver's own execute-method map | | Provider state | separately controlled by `mobile: toggleGps` | no provider toggle exists | The last row is the one people miss. Android models the *provider* and the *coordinates* as two different pieces of state; the Apple driver exposes only the simulated position. ## A worked example Suppose the swimming-lesson booking app opens on a pool-finder screen that lists nearby pools by distance. To assert that the city-centre pool comes first, the test has to put the device in the city centre before that screen loads: 1. Start the session with the app under test and the platform's usual capabilities. 2. Before navigating to the pool finder, send the platform's set-location command with the target latitude and longitude. 3. Open the pool finder and assert the ordering. 4. In teardown, send the platform's reset command so the next run does not inherit the position. Step 2 is the only line that differs between the Android run and the Apple run, and step 4 is the one most suites forget. ## What these commands do not do - They do **not** grant the application permission to read location; that is a separate driver surface with its own commands. - They do **not** guarantee the application notices immediately — an app holding a cached fix keeps showing it until it asks again. - They are **not** covered by `appium:noReset` or `appium:fullReset`, which govern the application's own state rather than the device's simulated position. - They do **not** share a name, so a helper that hard-codes `mobile: setGeolocation` throws on every Apple session in a mixed fleet. ## Getting it right in a cross-platform suite The practical shape is a thin adapter: one method on your driver wrapper that reads `platformName` from the live session and dispatches to the right execute method. Keep the branch in one place; the moment the command string appears in two page objects, one of them will drift. Do the same for the reset twin and call it from teardown rather than from individual cases, so a case that fails mid-flight still leaves the device clean. Finally, name the platform whenever you write or speak about this. `mobile: setGeolocation` and `mobile: setSimulatedLocation` are both real Appium commands, so a sentence that names one without naming its platform reads as authoritative and is wrong half the time. That is the whole point of this corner of the driver surface: both platforms can put a device somewhere, and they do not agree on a single word for it.

  • Which repository declares mobile: setGeolocation, and why does that matter when you go looking for its parameters?
    It is declared by `appium-android-driver`, the base driver that the UiAutomator2 and Espresso drivers both extend, so it is inherited rather than declared by either of them. The UiAutomator2 repository declares only its gesture and window execute methods, so searching there for `setGeolocation` finds nothing and people wrongly conclude the command does not exist. Look in the base Android driver's execute-method map instead.
  • How do you clear a simulated position at the end of a run on each platform?
    Send `mobile: resetGeolocation` on Android and `mobile: resetSimulatedLocation` on Apple platforms, from teardown rather than from the case body, so a case that fails mid-flight still leaves the device clean. Read the value back with `mobile: getGeolocation` or `mobile: getSimulatedLocation` when the hardware is shared. Do not expect `appium:fullReset` to do it — that governs the app's state, not the device's position.

saying these in an interview costs you the question

  • Believing one Appium command sets location on both platforms
  • Calling mobile: setGeolocation a UiAutomator2 driver command
  • Expecting appium:fullReset to clear a simulated location
  • Treating mobile: setSimulatedLocation as its own HTTP endpoint
  • Assuming setting coordinates also grants the app location permission