skip to content

In Appium, when does an Android install need mobile: installMultipleApks instead of mobile: installApp?

level: seniorimportance: nice to knowfreq 34%

answer

  1. one artifact, or a set
  2. bundles explode into splits
  3. base split installs, then crashes
  4. UiAutomator2 declares the multi-apk method
  5. no Apple twin: one archive

basics

~20 s

Use it when an Android build ships as separate split APKs rather than one file. UiAutomator2's mobile: installMultipleApks lands the whole split set in one transaction; mobile: installApp takes a single artifact, and Apple platforms have no multi-artifact twin.

solid answer

~50 s

On Android an app bundle is not what lands on the device. The build tooling turns it into a base split plus configuration splits — per density, per ABI, per language — and the package manager wants the subset a device needs installed as one atomic set. `mobile: installApp`, declared by `appium-android-driver` and inherited by both the UiAutomator2 and Espresso drivers, takes **one** artifact: a single `.apk`, or an `.apks` archive that already carries the set. When your beekeeping hive-log pipeline hands you loose split files instead, UiAutomator2 declares `mobile: installMultipleApks` in its own execute-method map, and it takes a list of paths and installs them together. Install the base split alone and the app installs, reports as present, and dies at launch on a resource that never arrived. Apple platforms have no counterpart, because an `.ipa` or `.app` is already one archive.

go deeper

for a junior

Know that Android can ship a build as several split files while an Apple build is one archive, and that Appium has a separate Android command for the multi-file case.

for a middle

Be ready to say which driver declares each command: mobile: installApp comes from the shared Android base driver, mobile: installMultipleApks is UiAutomator2's own, and Apple platforms have neither problem nor twin.

for a senior

Show that you can recognise a partial split install from its symptom — a clean install followed by a launch crash on missing resources — and that you fix it in setup rather than retrying the test.

for a principal

Own the decision one level up: whether the pipeline emits a single archive so every lane keeps one install path, or emits splits and the Android lane carries a branch no Apple lane will ever need.

## Why an Android build is sometimes several files A modern Android build is often published as an app bundle, and a bundle is not what a device installs. The publishing tooling turns it into a **base split** plus a set of **configuration splits** — typically one per screen density, one per CPU ABI, and one per language — so a given phone receives only the pieces it needs. The package manager then treats that subset as **one atomic install**: the splits belong to a single package and go on together or not at all. That leaves a test suite holding one of three shapes: - a single `.apk`, the classic one-file build; - an `.apks` archive, which already carries the split set inside one file; - loose split files, which is what a bundle-based pipeline usually produces. The first two are one artifact. The third is not, and that asymmetry is the entire reason a second install command exists. ## The two Android install commands, and which driver declares each - `mobile: installApp` is declared by **`appium-android-driver`**, the base driver that the UiAutomator2 and Espresso drivers both extend, so a session on either inherits it. It takes **one** artifact path. - `mobile: installMultipleApks` is declared by the **UiAutomator2 driver itself**, in its own execute-method map alongside its gesture and window commands. It takes a **list** of artifact paths and installs them as a single transaction. Attribution matters more than usual here. Writing *UiAutomator2's `mobile: installApp`* reads as true token by token and is wrong: that method comes from the shared Android base driver, while `mobile: installMultipleApks` genuinely is UiAutomator2's own — which also means an Espresso session, which inherits the base driver's list, does not get it. Both are reached the same way, as execute methods posted to a live session. ## What goes wrong when only part of the set lands Installing the base split alone rarely fails loudly. Walk it through for a beekeeping hive-log app whose high-density hive-diagram drawables and translated inspection labels live in configuration splits: 1. The install succeeds, because the base package is valid and self-consistent on its own. 2. `mobile: isAppInstalled` returns true, so a naive setup check passes. 3. The app launches, resolves a resource that lives in a split that never arrived, and dies. 4. The failure surfaces inside your first real test, several steps from its cause, and reads like an application bug rather than a setup bug. That distance between cause and symptom is why the choice belongs in setup and deserves to be deliberate: a suite that installs with the wrong command produces failures that look like anything except an install problem. ## Apple platforms have no multi-artifact twin The XCUITest driver declares `mobile: installApp`, `mobile: removeApp` and `mobile: isAppInstalled`, and nothing multi-artifact — because there is nothing to be multiple. An Apple build arrives as a single `.ipa` archive or a single `.app` bundle, with per-architecture and per-resource variation packed inside one container instead of spread across sibling files. | | Android | Apple platforms | |---|---|---| | single-artifact install | `mobile: installApp`, from `appium-android-driver` | `mobile: installApp`, XCUITest's own | | multi-artifact install | `mobile: installMultipleApks`, UiAutomator2's own | none — the artifact is already one file | | artifact shapes | `.apk`, `.apks`, or loose splits | `.ipa` or `.app` | Read that table as the point of the whole subject: the command name is shared, the artifact model is not, and a cross-platform helper that assumes one file per install is quietly Android-incomplete. ## What a suite should actually do - Decide at build time which shape your pipeline produces, and make the install step accept that shape rather than discover it at run time. - If the pipeline hands you loose splits, call UiAutomator2's `mobile: installMultipleApks` and pass the whole set — never only the base. - If you would rather keep one code path, have the pipeline emit a single `.apks` archive and stay on `mobile: installApp`. - Do not port a multi-artifact branch into the Apple lane: there is no method to call and no second file to pass. - Treat installed as a claim you verify. `mobile: isAppInstalled` answers whether an identifier is present, not whether the build behind it is complete or current. - Keep the choice of command visible in the suite log, so a launch crash can be traced back to a partial install in seconds. The last two points are what separate a team that has been bitten from one that has not. Both platforms will report an app as installed when what is on the device is a partial split set on Android, or a stale build carrying the same identifier on either platform. Install is the first thing a mobile suite does and the first thing it can silently get wrong.

  • How would you tell from a failing run that only the base split of an Android build was installed?
    The signature is an install that reports success and an app that dies at or just after launch, on missing resources rather than on your test's first assertion. Check what the pipeline handed the suite: if it produced loose splits and setup called `mobile: installApp` with one path, the rest never arrived. Reinstall the full set with UiAutomator2's `mobile: installMultipleApks` and the symptom disappears.
  • Why does an Espresso session not have mobile: installMultipleApks?
    Because it is declared in the UiAutomator2 driver's own execute-method map, not in `appium-android-driver`. Espresso extends that same Android base driver and inherits the base list — `mobile: installApp`, `removeApp`, `isAppInstalled` and the rest — but not another driver's private additions. If an Espresso lane needs a split build, produce a single `.apks` archive for it instead.

A bundle is flat-pack furniture delivered in several boxes: the box holding the frame is a complete parcel on its own, and you only discover the shelves are missing once you try to use it.

saying these in an interview costs you the question

  • Assumes every Android build installs as one file
  • Thinks Apple platforms have a multi-apk equivalent
  • Attributes mobile: installApp to the UiAutomator2 driver
  • Treats isAppInstalled as proof the split set landed
  • Installs only the base split and blames the app