skip to content

In Appium, how do you dismiss the soft keyboard after typing on Android and on iOS?

level: seniorimportance: should knowfreq 58%

answer

  1. the next step fails, not this one
  2. same two methods, both platforms
  3. the capability is Android's alone
  4. query before you continue
  5. old keyboard routes survived

basics

~20 s

Both the Android drivers and the XCUITest driver declare mobile: hideKeyboard and mobile: isKeyboardShown, and Appium's core route table still answers the older hide-keyboard and is-keyboard-shown endpoints. Only Android adds a capability, appium:hideKeyboard. Verify with the query rather than assuming.

solid answer

~40 s

Dismissal is the second half of text entry, and it is the half that breaks the *next* step rather than the current one. Both sides expose the same two execute methods — `mobile: hideKeyboard` and `mobile: isKeyboardShown` — and Appium's core route table still carries `POST /session/:sessionId/appium/device/hide_keyboard` and `GET /session/:sessionId/appium/device/is_keyboard_shown`, which survived Appium 3's cull of the `/appium/...` surface. The divergence sits above them: `appium:hideKeyboard` is an Android capability with no iOS twin, so Android can be configured once per session while iOS is dismissed per interaction. Treat dismissal as fallible: call the hide method, then query `mobile: isKeyboardShown` and act on the answer rather than sleeping and hoping.

code

bash · 3 lines
bash
curl -sS -X POST http://127.0.0.1:4723/session/$SESSION/execute/sync \
  -H 'Content-Type: application/json' \
  -d '{"script": "mobile: hideKeyboard", "args": [{}]}'

go deeper

for a junior

Remember that the keyboard stays up after you type and can cover the control you need next, so dismissing it is part of the step rather than an afterthought.

for a middle

Be ready to name mobile: hideKeyboard and mobile: isKeyboardShown on both platforms and to say that the appium:hideKeyboard capability is the Android drivers' with no iOS twin.

for a senior

Show that you verify dismissal with the query method and branch on the result, and that you can recognise a covered control as a keyboard problem rather than a locator problem.

for a principal

Decide how the asymmetry is carried across the fleet — a session-level capability on one lane, explicit calls on the other — and keep that difference visible instead of buried in a helper.

## Why dismissal is a first-class problem Entering a vessel name into a fishing-quota logging app is only half the interaction. The soft keyboard is still up afterwards, covering the lower part of the screen — which is where the catch-weight field, the species picker and the save button usually live. The symptom is never "typing failed". It is the next step failing: an element found but not reachable, a tap landing on a key instead of a control, a scroll that moves the wrong container. That misdirection is why keyboard dismissal earns its own interview question. ## The commands, on both platforms The good news is that this is one of the few places on this tree where the names line up: - **`mobile: hideKeyboard`** is declared by the Android drivers and by the XCUITest driver. - **`mobile: isKeyboardShown`** is likewise declared on both sides, and it is the query that turns dismissal from a hope into a check. - Both are sent as a `mobile:` name plus one parameter map to `POST /session/:sessionId/execute/sync`. - The older core routes still exist: `POST /session/:sessionId/appium/device/hide_keyboard` and `GET /session/:sessionId/appium/device/is_keyboard_shown` remain in Appium's core route table. Appium 3 removed a large block of the `/appium/...` endpoint surface in favour of driver execute methods, but the keyboard pair survived the cull — so do not tell a colleague those endpoints are gone. ## Where the two platforms diverge | | Android (the Android drivers) | iOS (XCUITest) | |---|---|---| | Dismiss method | `mobile: hideKeyboard` | `mobile: hideKeyboard` | | Query method | `mobile: isKeyboardShown` | `mobile: isKeyboardShown` | | Session-level capability | `appium:hideKeyboard` | none | | Related legacy capability | `appium:unicodeKeyboard`, which the UiAutomator2 README says `appium:hideKeyboard` supersedes and expects to drop | not applicable | | The keyboard's own action key | `mobile: performEditorAction` | not applicable | The capability row is the one that matters in design. On Android you can express a session-wide intent with `appium:hideKeyboard` and stop thinking about it; on iOS there is no equivalent switch, so dismissal is something the test code does where it needs it. A cross-platform helper that assumes a capability handles this everywhere will quietly do nothing on one of the two lanes. The second divergence is Android's `mobile: performEditorAction`, which fires the keyboard's own action key. On a catch-entry form, firing the editor action is often better than dismissing the keyboard at all: it commits the field the way a user would and lets the app decide what happens next. There is no equivalent on the iOS side of the fence. ## Making dismissal deterministic 1. **Decide whether you need dismissal or submission.** If the flow's next move is "the user is done with this field", Android's editor action models it better than hiding the keyboard behind the app's back. 2. **Call the hide method, then query.** `mobile: isKeyboardShown` exists precisely so you do not have to assume; a hide request is not a guarantee. 3. **Branch on the answer, do not sleep.** If the keyboard is still shown, you have a real condition to handle — a keyboard with no dismissal control, a focus that moved — not a timing problem to wait out. 4. **Set the Android capability once** rather than calling the method in twenty places, and keep the iOS path explicit so the asymmetry stays visible. 5. **Assert on the control you actually need next**, not on the keyboard. The keyboard is a means; the test cares that the save button is reachable. ## The failure modes worth naming - A dismissal that reports success while the keyboard is still up, because nothing was verified afterwards. - A shared helper whose capability-based Android path silently does nothing on iOS. - A fixed sleep standing in for the query method, which turns a deterministic check into a slow gamble. - Reaching for a hardware-button command to dismiss the keyboard; physical buttons are a different mechanism and a different subject. - Assuming Appium 3 deleted the older hide-keyboard route and rewriting working code for no reason. ## The summary The methods are shared, the capability is not, and the query is what makes either safe. Name the platform whenever you discuss it, because "just hide the keyboard" is two different pieces of engineering depending on which driver answered your session request.

  • Why prefer Android's mobile: performEditorAction over hiding the keyboard?
    Because it models what a user does: it fires the keyboard's own action key, committing the field and letting the app react — validating, moving focus, or submitting. Hiding the keyboard removes the obstruction without telling the app anything happened, which can leave the screen in a state a real user never reaches. It is an Android-only option.
  • What makes a keyboard dismissal worth verifying rather than trusting?
    The request being accepted only means the driver took it. Whether the keyboard actually went away depends on the keyboard the app is showing and on where focus went. `mobile: isKeyboardShown` is declared on both platforms for exactly this, and branching on its answer is cheaper and far more diagnostic than a sleep.

saying these in an interview costs you the question

  • Sleeping after dismissal instead of querying the keyboard
  • Assuming one capability hides the keyboard on both platforms
  • Claiming Appium 3 removed the hide-keyboard endpoint
  • Blaming an unreachable save button on locator flake
  • Using a hardware-button command to dismiss the keyboard