skip to content

In Appium, what is the page-source tree actually built from on Android compared with iOS?

level: middleimportance: must knowfreq 58%

answer

  1. two producers, not one tree
  2. accessibility hierarchy on Android
  3. XCUIElement snapshot on Apple platforms
  4. neither is the app's view hierarchy
  5. the producer decides what is addressable

basics

~20 s

Android's UiAutomator2 driver serialises the accessibility node hierarchy the platform publishes. Apple's XCUITest driver serialises an XCUIElement snapshot WebDriverAgent takes through XCTest. Neither is the app's own view hierarchy, so whatever those layers withhold is unaddressable.

solid answer

~50 s

Neither tree is your app's view hierarchy. On Android the UiAutomator2 driver's on-device server walks the **accessibility node hierarchy** the platform publishes and serialises that; nodes the accessibility layer never exposes simply are not there. On Apple platforms WebDriverAgent asks XCTest for an `XCUIElement` **snapshot** of the application it treats as active and serialises that instead. Two consequences follow. First, the vocabularies differ: Android nodes carry widget class names, Apple nodes carry `XCUIElementType…` names, so no single XPath spans both. Second, and more important, addressability is decided upstream of your locator: a custom-drawn glossary term that publishes nothing to accessibility, or a node beyond the driver's snapshot bounds, cannot be matched by any strategy that resolves against that tree — the fix is in the app or in the driver's settings, not in the selector.

go deeper

for a junior

Be ready to say that the tree comes from the platform's accessibility layer on Android and from an XCUIElement snapshot on Apple platforms, and that neither is the app's own view hierarchy.

for a middle

Be ready to trace the mechanics: which component builds each tree, what its default scope is, and which settings change scope, visibility and depth on each platform.

for a senior

Be ready to decide, in front of a failing suite, whether a missing node is an application accessibility defect or a driver-bounds problem, and to defend which of the two you fix.

for a principal

Be ready to set the standard: treat addressability as an accessibility obligation the app owns rather than something a suite patches per platform with ever-wider snapshot settings.

## Two producers, two trees Appium's page source looks like one feature with one name, and it is two mechanisms wearing the same label. Knowing which mechanism you are talking to is the difference between fixing a locator and fixing an app. On **Android**, the UiAutomator2 driver installs and runs an on-device server, `io.appium.uiautomator2.server`. It does not read your `View` objects. It reads the **accessibility node hierarchy** the platform publishes — the same hierarchy an assistive technology consumes — and serialises that into XML. On **Apple platforms**, the XCUITest driver drives **WebDriverAgent**, which asks XCTest for an `XCUIElement` **snapshot** of the application it considers active and serialises that. Both are proxies for the real interface, produced by an operating-system layer that has its own opinions about what is worth publishing. | | Android — UiAutomator2 | Apple — XCUITest | | --- | --- | --- | | Producer | `io.appium.uiautomator2.server` on the device | WebDriverAgent, via XCTest | | Underlying model | accessibility node hierarchy | `XCUIElement` snapshot | | Scope by default | the active window | the application treated as active | | Scope controls | `enableMultiWindows`, `enableTopmostWindowFromActivePackage`, `currentDisplayId` | `defaultActiveApplication`, `activeAppDetectionPoint` | | Visibility filter | `allowInvisibleElements`, `ignoreUnimportantViews` | `includeHittableInPageSource`, `includeNativeAccessibilityElementInPageSource` | | Depth and breadth bounds | `snapshotMaxDepth` | `snapshotMaxDepth`, `snapshotMaxChildren` | ## Android: the accessibility node hierarchy Because the Android tree is the accessibility tree, everything the accessibility framework does to a screen happens to your test's view of it. Two settings make this concrete. `ignoreUnimportantViews` lets the driver skip nodes the platform marks unimportant for accessibility, which shrinks the tree and can remove a wrapper your XPath was stepping through. `allowInvisibleElements` decides whether nodes the platform reports as not visible appear at all. And `enableMultiWindows` matters because the default scope is a single window: in a translation-glossary app, a definition rendered into a separate window layer is outside the dump until that setting widens the scope. ## Apple platforms: the XCUIElement snapshot On the Apple side the tree is whatever XCTest hands WebDriverAgent when it takes a snapshot of the active application. "Active application" is a decision, not a fact, which is why XCUITest exposes `defaultActiveApplication` and `activeAppDetectionPoint` to steer it. Breadth as well as depth is bounded here: `snapshotMaxChildren` caps how many siblings are taken at a level, a control the Android side does not have, and `snapshotMaxDepth` caps how deep the walk goes. What each node carries is configurable too, through `includeHittableInPageSource`, `includeMinMaxValueInPageSource`, `includeCustomActionsInPageSource` and `pageSourceExcludedAttributes`. ## Why the producer decides what is addressable This is the point the leaf exists to make: - A locator can only match a node that reached the tree. The driver builds the tree first and matches second. - If the accessibility layer on Android never publishes a custom-drawn glossary cell, no `class name`, no `accessibility id` and no XPath will reach it, and adding a test id in the app is the only fix. - If a bound truncates the tree — depth on either platform, breadth on Apple platforms — the node is absent for exactly the same reason, but the fix is a driver setting rather than an app change. - Because the vocabularies differ, an XPath tuned on an Android dump is not "nearly right" for iOS; it is addressing a different model. - The dump and the driver's tree-walking finds come off the same bounded tree, so what you cannot see in the dump you generally cannot match with a strategy resolved from it. There is one honest caveat worth keeping in mind: some strategies are evaluated by the on-device engine rather than resolved from the serialised XML, so "absent from the dump" is strongest as a statement about the tree the driver built, not as a universal law about every selector engine. In practice, for the tree-walking strategies teams actually reach for, the rule holds. ## What this means for a translation-glossary suite 1. Before blaming a locator, dump the source on the platform that failed and search it for the term. Absence and presence lead to different repairs. 2. Keep two mental models, not one. "The glossary row is a node in the accessibility hierarchy" on Android; "the glossary row is an element in an `XCUIElement` snapshot" on Apple platforms. 3. When a term is genuinely invisible to the producing layer, treat it as an application defect — an unlabelled custom cell is as inaccessible to a screen reader as it is to your suite. 4. Record which settings a suite changes per platform, because those settings are part of what your locators assume. A candidate who can say *what produces the tree* on each platform, and can then reason from that to why a locator failed, is demonstrating exactly the layer beneath everyday API use that a mid-level interview is looking for.

  • A custom-drawn glossary cell is missing from the Android page source. Is that an Appium bug?
    No. The UiAutomator2 driver serialises the accessibility node hierarchy, so a cell that publishes nothing to that layer is invisible to the driver by construction. The repair belongs in the app — give the cell a content description or a resource id — which also makes it reachable for assistive technology.
  • Why can the same XPath expression work on Android and return nothing on iOS?
    The two dumps are different models. Android nodes carry widget class names from the accessibility hierarchy; Apple nodes carry `XCUIElementType…` names from an `XCUIElement` snapshot. A path built out of one vocabulary has nothing to match in the other, so cross-platform suites need per-platform locators rather than one shared expression.

The page source is a photograph of the screen taken through the operating system's accessibility lens, not a window onto the app's own view objects. Whatever the lens crops out never reaches the film, so no amount of squinting at the print will bring it back.

saying these in an interview costs you the question

  • Claiming Appium reads the app's own view hierarchy directly
  • Assuming one XPath can span the Android and iOS trees
  • Believing anything visible on screen must be in the dump
  • Blaming the locator when the node never reached the tree
  • Treating the Apple snapshot as covering every window at once