skip to content

Entering Text

Getting text into a field and then getting the soft keyboard back out of the way - the part of a mobile suite that breaks on Unicode, on typing speed, and on a keyboard covering the next target.

on this pageshow

explore

questions

5

In Appium, which request types text into a native field on Android and on iOS?

level: middleimportance: must knowfreq 74%

answer

  1. one W3C endpoint, two agents
  2. the body carries text
  3. Android agent versus WebDriverAgent
  4. only iOS bounds typing rate
  5. maxTypingFrequency is XCUITest's

basics

~20 s

Both platforms answer POST /session/:sessionId/element/:elementId/value with a text field. On Android the UiAutomator2 agent performs the typing; on iOS WebDriverAgent does, at a rate the maxTypingFrequency setting bounds. Each driver adds its own typing methods.

solid answer

~40 s

Text entry is one of the few interactions that looks identical at the protocol level: you post a body carrying `text` to `/session/:sessionId/element/:elementId/value`, and both the UiAutomator2 driver on Android and the XCUITest driver on iOS answer it. What differs is everything underneath. On Android the command is served by the driver's on-device server, and the Android drivers add `mobile: type` and `mobile: replaceElementValue` plus the `appium:hideKeyboard` capability. On iOS WebDriverAgent drives the keyboard the app is showing, so the XCUITest settings `maxTypingFrequency`, `keyboardAutocorrection` and `keyboardPrediction` decide whether what you sent is what lands. Treat the shared endpoint as a shared entry point, not shared behaviour — assert the field's contents afterwards on both platforms.

code

bash · 3 lines
bash
curl -sS -X POST http://127.0.0.1:4723/session/$SESSION/element/$ELEMENT/value \
  -H 'Content-Type: application/json' \
  -d '{"text": "Njord II bluefin 12.5 kg"}'

go deeper

for a junior

Know the request by name: post to the element's value route with a text field, and remember that Appium inherits it from WebDriver rather than inventing it.

for a middle

Be ready to say who answers the request on each platform — the UiAutomator2 on-device server on Android, WebDriverAgent on iOS — and to name one typing control that exists on only one of them.

for a senior

Show that you verify the field afterwards instead of trusting the send, and that you can explain a text assertion passing on Android and failing on iOS without calling it flake.

for a principal

Own the decision about where the platform branch lives and how much of it a shared helper may hide, given that hidden divergence turns a real iOS defect into an unexplained retry.

## The one request both platforms answer Appium is a WebDriver server, so it inherits WebDriver's element-send-keys command unchanged: `POST /session/:sessionId/element/:elementId/value`, with the string to enter carried in the body's `text` field. That single request is what fills the vessel-name box on the catch-entry screen of a fishing-quota logging app, and it is the same request whether the session was started with the UiAutomator2 driver against an Android phone or with the XCUITest driver against an iPhone. Nothing above the endpoint distinguishes the two, which is exactly why a shared page object for a form compiles, runs, and looks like it works — right up to the first non-ASCII vessel name. ## What sits on the other side of the endpoint Underneath that shared request the two drivers hand the work to entirely different machinery, and the difference is the content of this topic. - On **Android**, the UiAutomator2 driver proxies the command to the on-device server it installs and starts for the session, `io.appium.uiautomator2.server`. - On **iOS**, the XCUITest driver proxies to **WebDriverAgent**, an XCTest runner that `xcodebuild` builds and installs, which drives the app through Apple's own automation framework. - Each driver then adds typing surface the other does not have. UiAutomator2 declares `mobile: type` and `mobile: replaceElementValue` in its own execute-method map; XCUITest declares `mobile: keys` for key sequences. Physical buttons are a different command on both platforms and a different subject. - Keyboard visibility has methods on both sides — `mobile: hideKeyboard` and `mobile: isKeyboardShown` — but the capability `appium:hideKeyboard` belongs to the Android drivers and has no iOS twin. ## The knobs diverge even where the endpoint does not | Concern | Android (UiAutomator2 and the Android drivers) | iOS (XCUITest) | |---|---|---| | Entry point | `POST /session/:sessionId/element/:elementId/value` with `text` | the same request | | Extra typing methods | `mobile: type`, `mobile: replaceElementValue` | `mobile: keys` | | Keyboard visibility | `mobile: hideKeyboard`, `mobile: isKeyboardShown`, plus the `appium:hideKeyboard` capability | `mobile: hideKeyboard`, `mobile: isKeyboardShown` | | Fidelity controls | the legacy `appium:unicodeKeyboard` capability, which the UiAutomator2 README says `appium:hideKeyboard` supersedes and expects to drop | the settings `maxTypingFrequency`, `keyboardAutocorrection`, `keyboardPrediction`, `useClearTextShortcut` | The iOS column is the one that surprises people. Because WebDriverAgent goes through the keyboard the app is actually showing, iOS text entry inherits that keyboard's behaviour: autocorrection and predictive suggestions can rewrite what you sent, and the rate at which characters are delivered is itself tunable through `maxTypingFrequency`. Android exposes no equivalent pair. So a suite that is green on Android and wrong on iOS for the same catch-log form is a normal outcome, not a mystery — the two runs did not do the same thing. ## Why one endpoint still needs two tested paths The practical consequences of that divergence, in the order teams usually meet them: 1. **A long string can arrive truncated on iOS and intact on Android**, because only one platform has a delivery-rate setting to get wrong. 2. **A string can arrive changed on iOS** — corrected or completed by the keyboard — while Android delivers it verbatim. 3. **A field that already holds text behaves differently depending on which command you used**, and only the Android drivers offer a replace-shaped execute method for it. 4. **The keyboard left standing after the send covers the next control**, and the dismissal story is a capability on one platform and a per-call method on both. None of those is visible in the request you wrote. All four are visible in the field afterwards, which is why the single most valuable habit here is to read the value back and assert on it rather than trusting that an accepted request means the right characters landed. ## Writing text entry so it survives both platforms - Use the shared value endpoint as the default path, so the common case stays one line in a page object. - Assert the field's contents after entry in at least the cases that carry awkward text — non-ASCII vessel names, long species descriptions, decimal quota weights. - Pin the iOS typing settings at session start rather than mid-test, so they live in configuration next to the other capabilities instead of in a helper nobody reads. - Keep the platform branch visible where behaviour genuinely differs; hiding it makes an iOS-only autocorrection defect look like an intermittent failure. - Never write one sentence in a review or a bug report that covers both platforms' typing behaviour — name the driver, because the mechanism is not shared. The short version worth carrying into an interview: the request is shared, the agent answering it is not, and every knob that decides whether typed text is correct lives on exactly one of the two platforms.

  • If the same request reaches both platforms, why can one test still need two expectations?
    Because the request is only the entry point. On Android the UiAutomator2 agent performs the entry; on iOS WebDriverAgent goes through the app's own keyboard, where autocorrection, prediction and the delivery rate can alter the string. What you sent and what the field holds can therefore differ on one platform and not the other.
  • Which extra typing commands does each driver add on top of that endpoint?
    The UiAutomator2 driver declares `mobile: type` and `mobile: replaceElementValue` in its own execute-method map; the XCUITest driver declares `mobile: keys` for key sequences. Both sides also expose `mobile: hideKeyboard` and `mobile: isKeyboardShown`, but only the Android drivers offer the `appium:hideKeyboard` capability.

saying these in an interview costs you the question

  • Assuming one shared endpoint means shared typing behaviour
  • Treating an accepted request as proof the characters landed
  • Naming maxTypingFrequency as an Android control
  • Saying the driver types the same way on both platforms
  • Never reading the field back after entering text
open as a page

Your Appium iOS session mistypes a fishing-quota vessel name — which XCUITest settings do you check?

level: seniorimportance: must knowfreq 52%

basics

~20 s

Classify the damage first. Missing characters point at maxTypingFrequency, the XCUITest setting bounding delivery rate. Substituted or completed words point at keyboardAutocorrection and keyboardPrediction, where the app's own keyboard rewrote the entry. Leftover text points at useClearTextShortcut.

open as a page

In Appium on Android, when should a test use mobile: replaceElementValue rather than send keys?

level: middleimportance: should knowfreq 55%

basics

~20 s

Use it when the field must end up holding exactly one string. UiAutomator2's mobile: replaceElementValue replaces an element's value, while the shared send-keys endpoint enters text into the field as it stands. Send keys when the app reacts per keystroke.

open as a page

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

level: seniorimportance: should knowfreq 58%

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.

open as a page

How would you design one Appium text-entry helper for a fishing-quota app on Android and iOS?

level: principalimportance: should knowfreq 42%

basics

~20 s

Share the send-keys endpoint and the read-back assertion; branch everything else. Android gets replace-shaped entry and the hide-keyboard capability, iOS gets typing-fidelity settings pinned at session start. Keep the branch visible so an iOS-only defect never reads as flake.

open as a page