skip to content

In Appium, what makes `accessibility id` the one locator that travels between Android and iOS?

level: middleimportance: should knowfreq 46%

answer

  1. the request travels, the field does not
  2. two drivers, one strategy name
  3. no translation happens anywhere
  4. portable only per element, by hand

basics

~20 s

Both drivers declare the strategy and both compare a plain string, so an identical find request is legal on either platform. The travelling is done by the application, which must carry the same string in two unrelated app-side fields.

solid answer

~40 s

Two things travel and one thing does not. What travels is the **request**: the UiAutomator2 driver and the XCUITest driver both declare `accessibility id`, so the same `using` and `value` pair is a legal find on either session, with no branching in the test. What does not travel is the **field**: Android compares that string against `content-desc`, Apple platforms against `name`, which is `accessibilityIdentifier` or the visible `label`. No driver translates one into the other. The address is portable only because someone wrote the same string into both builds, and nothing enforces that they stay in step — so portability here is a property the application keeps, per element, not a feature the tool provides.

code

json · 4 lines
json
{
  "using": "accessibility id",
  "value": "turnstile-scan-gate"
}

go deeper

for a junior

Know that the same find request is legal on both platforms and that the underlying fields differ. Being able to say the strategy is shared but the field is not covers most of what is asked at this stage.

for a middle

Explain both halves: the drivers guarantee the strategy, the build guarantees the value. Be able to name the Android field and the Apple one, and say that nothing reconciles them for you.

for a senior

Show how you verify a shared address instead of assuming it, and describe how a one-sided address shows up differently on each platform because only Apple platforms have the label fallback to mask it.

for a principal

Be ready to argue for the shared address as an unenforced cross-repository convention: say what makes it worth the discipline it demands, and how you would notice on the day the two builds drift apart.

## What is genuinely shared Across an Appium suite that drives the same stadium turnstile product on both platforms, exactly two things about an `accessibility id` lookup are identical: - **The strategy name.** Both the UiAutomator2 driver on Android and the XCUITest driver on Apple platforms declare `accessibility id` among their locator strategies, so the client does not have to branch on platform to build the request. - **The wire request.** The find body carries `using` set to `accessibility id` and `value` set to your string. It is the same request on either session, which is why a page object can hold one constant instead of two. That is a real and valuable property. Most of the other strategies are one platform's dialect, so a suite built on them ends up as two suites wearing one name. This is the one address that lets a single line of test code mean the same thing twice. ## What is not shared at all The resolution is entirely per platform, and nothing in the server bridges it. | | Android (UiAutomator2) | Apple platforms (XCUITest) | |---|---|---| | Attribute compared | `content-desc` | `name` | | App-side source | `contentDescription` | `accessibilityIdentifier` | | Behaviour when unset | the find fails | falls back to the element's `label` | | Who keeps the two in step | the application team | the application team | Read the last row twice, because it is the answer to the question. The driver performs no translation, no aliasing across platforms and no reconciliation. It compares your string against a field that its own platform already exposed for accessibility purposes, and stops there. ## Portability is an application property The useful way to hold this is that `accessibility id` gives you a shared **namespace**, not a shared **value**. The namespace is guaranteed by the drivers; every value in it is a manual, per-element promise kept by the build. Consequences worth stating out loud: - It is granular. The promise is kept or broken **per element**, so a screen can be fully addressable on both platforms except for the one control your new case needs. - It is unenforced. No gate, no capability and no server check compares the Android build's descriptions with the Apple build's identifiers. - It is silent when half-kept. A one-sided address fails outright on Android and may still pass on Apple platforms through the label fallback, so the failure is not even symmetrical. - It is only as stable as the values chosen. A token that could plausibly be product copy invites a caption match on Apple platforms and tells you nothing when it succeeds. ## A worked shape On a turnstile entry screen, the Android build exposes `turnstile-scan-gate` as the scan button's description and the Apple build sets the same string as that button's identifier. One locator now addresses both, and it survives layout changes, restyling and re-ordering, because neither field is derived from position or presentation. Change one build and not the other and the shared address quietly becomes a platform-specific one — the test does not announce the change, it just fails on one lane and passes on the other. ## How to judge whether an address really is shared Before treating a locator as cross-platform, confirm it rather than assume it: 1. Run the same find on both platforms against the same build pair, not just on the platform you are currently debugging. 2. On Android, confirm the element's `content-desc` holds the token. 3. On Apple platforms, confirm the element's `name` holds the token **and** that the token is not simply the visible caption. 4. Re-run the Apple-platform check in a second display language if the product is localised; a caption match will change and an identifier match will not. 5. Only then reduce the two platform constants in the page object to one. ## Where the portability stops Be honest about the limits when you describe the strategy. It carries a plain string, so it addresses one element by one token; it does not express structure, relationships, ordering or partial matching, and it cannot describe a control that carries no accessibility field on either platform. When a control genuinely has no shared address, the answer is to give it one in both builds rather than to invent a cross-platform expression on top of two platform-specific dialects — that route reintroduces exactly the two-suites-in-one-name problem the shared address exists to avoid. ## What an interviewer is listening for Anyone can say `accessibility id` is the cross-platform locator. The answer that lands separates the mechanism from the promise: the drivers guarantee the strategy exists on both sides, and the application guarantees the value exists on both sides — and only the first of those two guarantees is enforced by anything.

  • If the strategy is shared, why can the same locator still make a suite behave like two suites?
    Because only the request is shared. The Android build must carry the token in `content-desc` and the Apple build in `accessibilityIdentifier`, kept in step by hand. When one side drifts, the locator addresses a real element on one platform and nothing — or the wrong thing — on the other.
  • What kind of string makes a good shared accessibility id value?
    One that could never be mistaken for product copy, such as a hyphenated token like `turnstile-scan-gate`. On Apple platforms it makes a successful match self-evidently an identifier match rather than a fallback onto the visible label, and it stays stable through copy edits and translation.

saying these in an interview costs you the question

  • Says the driver translates the address between the two platforms.
  • Treats portability as a tool feature rather than an app-side promise.
  • Assumes one screen being addressable means every element is.
  • Believes a shared strategy name implies a shared underlying field.
  • Expects some gate to warn when only one build carries the token.