skip to content

In Appium, which execute method presses a hardware key on Android, and which one on iOS?

level: juniorimportance: should knowfreq 66%

answer

  1. the two platforms share no call
  2. one takes a number, one a name
  3. Android KeyEvent keycode, Apple button label
  4. UiAutomator2 declares one, XCUITest the other

basics

~10 s

On Android, UiAutomator2 exposes mobile: pressKey, taking a numeric Android KeyEvent keycode. On Apple platforms, XCUITest exposes mobile: pressButton, taking a named button such as volumeup. Neither call exists on the other platform.

solid answer

~40 s

Hardware keys are one of the places Appium does not paper over the platforms. On Android, the UiAutomator2 driver's `mobile: pressKey` takes a **numeric** Android `KeyEvent` keycode — `4` for back, `24` for volume up — plus optional `metastate` and `isLongPress`. On Apple platforms, the XCUITest driver's `mobile: pressButton` takes a **name** from a short, closed set of physical buttons, such as `home`, `volumeup` or `volumedown`; there is no keycode and no long-press flag. Both travel as ordinary `mobile:` execute methods over `POST /session/:sessionId/execute/sync`. Appium 3's migration guide points the old `POST /appium/device/press_keycode` route at `mobile: pressKey` on Android and at XCUITest's `mobile: keys` on iPadOS. A cross-platform suite branches on `platformName`; it cannot share one call.

code

java · 22 lines
java
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;
import java.util.Map;

public final class KayakRentalHardwareKeys {

    private KayakRentalHardwareKeys() {
    }

    // Android, UiAutomator2 driver: a numeric KeyEvent keycode (24 = volume up).
    public static void volumeUpOnAndroid(AndroidDriver driver) {
        driver.executeScript("mobile: pressKey", Map.of(
                "keycode", 24,
                "isLongPress", false));
    }

    // Apple platforms, XCUITest driver: a named chassis button, never a number.
    public static void volumeUpOnApple(IOSDriver driver) {
        driver.executeScript("mobile: pressButton", Map.of(
                "name", "volumeup"));
    }
}

go deeper

for a junior

Be ready to name the two calls and say which driver owns each. Android takes a number and Apple platforms take a button name is an acceptable summary, as long as you attach each half to its platform.

for a middle

Explain the shape of each parameter map, and why one platform can accept an open integer space while the other accepts only a fixed list of chassis button names.

for a senior

Show that you know a hardware key is a device-level action with no element target, and describe how you confirm what actually had focus when a press produced nothing.

for a principal

Own the decision about whether a suite exposes a shared hardware-key abstraction at all, given that the two vocabularies do not map onto each other one for one.

## The problem hardware keys create A hardware key event is an input the application under test does not own. Tap a button inside the kayak-rental app and the tap is delivered to a view the app itself rendered; press volume-up while its booking calendar is on screen and the operating system, not the app, receives the event and decides who gets it. Appium therefore cannot express a hardware key as an element interaction — there is no element to send it to — and exposes it as a driver-level execute method instead. Because the two operating systems model that layer differently, the drivers model it differently too. This is one of the cases where the divergence **is** the content: there is no portable call, and a suite that pretends otherwise is hiding a branch it will have to write anyway. ## Android: `mobile: pressKey` on the UiAutomator2 driver The UiAutomator2 driver declares `mobile: pressKey` in its own execute-method map, next to its gesture and window commands. The parameter map is small: - `keycode` — a **number**, one of the Android platform's `KeyEvent` constants. `4` is back, `24` is volume up, `25` is volume down, `66` is enter. - `metastate` — an optional modifier bitmask, which is how Android says *this key was pressed while shift or control was held*. - `isLongPress` — an optional flag. Android models a long key press as a distinct kind of event rather than as a duration the caller times. The vocabulary is open-ended in the sense that matters: anything the platform can deliver as a key event has a number, and if you know the number you can send it. Nothing in the call names the kayak-rental app — the driver injects the event and the system routes it. ## Apple platforms: `mobile: pressButton` on the XCUITest driver The XCUITest driver declares `mobile: pressButton`, and its parameter is a **name**, not a number — `home`, `volumeup`, `volumedown`, and the remote-control buttons on tvOS. The set is short and closed because it describes the physical buttons on the device chassis, and a chassis button has no modifier state and no separate long-press event to flag. XCUITest also declares `mobile: keys`, which sends a sequence of keys to whatever the application currently has focused. That is the method for keyboard keys — Enter, Tab, Escape — as opposed to buttons on the case. Appium 3's migration guide makes the split explicit: it points the old `POST /appium/device/press_keycode` route at `mobile: pressKey` on Android and at `mobile: keys` on iPadOS. ## The two side by side | | Android (UiAutomator2) | Apple platforms (XCUITest) | |---|---|---| | Method | `mobile: pressKey` | `mobile: pressButton` | | Key identified by | numeric `KeyEvent` keycode | button name such as `volumeup` | | Modifiers | `metastate` bitmask | none on this method | | Long press | `isLongPress` flag | none on this method | | Keyboard keys | same method, different keycode | separate method, `mobile: keys` | Every row of that table is a place a cross-platform helper has to branch rather than translate. ## How the call reaches the driver Both are `mobile:` execute methods, which is Appium's general mechanism for anything outside the W3C WebDriver command set. The client posts to `POST /session/:sessionId/execute/sync` with the method name as the script and exactly one parameter map as the argument; a language client such as java-client wraps that in `executeScript("mobile: pressKey", Map.of(...))` and adds nothing of its own. Three consequences follow: 1. The method belongs to the **driver**, not to the Appium server, so it exists only in a session whose `appium:automationName` selected that driver. 2. Sending `mobile: pressButton` to a UiAutomator2 session, or `mobile: pressKey` to an XCUITest session, fails as an unknown method — there is no fallback and no translation. 3. Neither call takes an element parameter, so neither can be scoped to a view of the kayak-rental app. ## The attribution trap `mobile: pressKey` is not *Appium's* key command — it is the **UiAutomator2 driver's**, and naming it without the driver is the mistake that makes an answer sound right and be wrong. The same holds for `mobile: pressButton` on the XCUITest side. Mobile interviewers notice, because a candidate who names the driver has read a driver's own documentation rather than a post that flattened both platforms into one API. ## What a suite does with this - Branch on `platformName` at the point of the call, and keep the branch visible rather than buried in a helper that silently does nothing on one platform. - Do not build a translation table that maps a keycode onto a button name as though the two were the same alphabet; only a handful of keys exist on both sides at all. - Remember that some keys have no counterpart in either direction: Android's back key has no Apple chassis equivalent, and Apple's key-sequence method has no single Android twin.

  • Where does either of those hardware-key calls actually go over HTTP?
    Both are `mobile:` execute methods, so the client posts them to `POST /session/:sessionId/execute/sync` with the method name as the script and a single parameter map as the argument. Appium 3's migration guide points the old `POST /appium/device/press_keycode` route at `mobile: pressKey` on Android and at XCUITest's `mobile: keys` on iPadOS.
  • If a kayak-rental test needs a keyboard key rather than a chassis button on an Apple platform, what does XCUITest offer?
    `mobile: keys`, which sends a sequence of keys to whatever the application currently has focused. `mobile: pressButton` is for the physical buttons on the device case and its accepted names are a closed list, so Enter or Tab is simply not in its vocabulary.

saying these in an interview costs you the question

  • Claiming one Appium call presses hardware keys on both platforms
  • Passing a numeric keycode to the Apple driver's button method
  • Passing a button name such as volumeup to the Android key method
  • Believing Appium translates Android keycodes into Apple button names
  • Assuming the press targets a located element rather than the device
  • Naming the method without naming the driver that declares it