Appium Driver

jumpstarter-driver-appium gives every UI-automation target the same Appium client interface. Test code opens WebDriver sessions on one URL with the capabilities the target provides, whether the target is a physical device, an emulator or a simulator, on Android or iOS.

Appium is Jumpstarter’s default UI-automation framework: one WebDriver API for every platform it supports, an official Python client that installs with pip, and nothing to install on the client beyond that client library. See Appium UI Automation for the reasons in full and for setting up an exporter.

Target drivers add an appium child built on AppiumDriver. It runs an operator-installed Appium on the exporter for each lease, listening on exporter loopback only, and clients reach it over the lease through verified HTTPS.

Installation

$ pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple jumpstarter-driver-appium

The exporter needs Node.js, Appium and the Appium drivers for its targets, such as UiAutomator2 or XCUITest. Containerized exporters usually pin them in their image; see Appium UI Automation for an example. Jumpstarter does not bundle, download or build Appium, its drivers or WebDriverAgent.

To use the Python examples below, install Appium-Python-Client on the client. The client does not need Appium itself.

Configuration

Target drivers usually create the appium child and fix the capabilities that identify their device. AppiumDriver can also be configured directly:

export:
  appium:
    type: jumpstarter_driver_appium.driver.AppiumDriver
    config:
      executable: /opt/appium/node_modules/.bin/appium
      home: /opt/appium/home
      drivers: [uiautomator2]
      capabilities:
        platformName: Android
        appium:automationName: UiAutomator2
        appium:udid: emulator-5554

Parameter

Description

Default

executable

Appium launcher, resolved on the exporter’s PATH

appium

home

APPIUM_HOME holding the installed Appium drivers; set it, since Appium does not inherit the exporter’s APPIUM_* variables

none

drivers

Appium drivers to load; all installed ones when empty

[]

capabilities

Capabilities fixed on every session; clients cannot override them

{}

env

Extra environment for Appium, such as ANDROID_ADB_SERVER_PORT

{}

state_dir

Existing directory for the lease’s private state

system temporary directory

startup_timeout

Seconds to wait for Appium to become ready

60

max_upload_bytes

Largest application a client may upload

4 GiB

Usage

from appium import webdriver
from appium.options.common import AppiumOptions

from jumpstarter.common.utils import env

with env() as root, root.appium.serve() as target:
    options = AppiumOptions().load_capabilities(target.capabilities())
    driver = webdriver.Remote(target.url, options=options, client_config=target.client_config())
    try:
        print(driver.page_source)
    finally:
        driver.quit()

serve() starts the lease’s Appium on first use and yields an AppiumTarget:

  • url: a loopback HTTPS address that reaches the exporter’s Appium.

  • capabilities(): the capabilities the target fixes, such as platformName and appium:udid; add your own before opening a session. Host paths stay on the exporter and are not shown.

  • client_config(): an Appium-Python-Client configuration that trusts the lease’s certificate authority. Use ssl_context() or ca_file with other clients. Certificate and hostname verification stay enabled.

  • environment(): the caller’s environment plus JUMPSTARTER_APPIUM_URL, JUMPSTARTER_APPIUM_CAPABILITIES (JSON), JUMPSTARTER_APPIUM_CA_FILE and Node’s NODE_EXTRA_CA_CERTS, for tools written in other languages.

Closing the block removes the listener. Appium keeps running until stop(), reset or the end of the lease.

Applications

Appium on the exporter cannot read files on the client, so upload applications first and pass the returned token where Appium expects an application:

token = root.appium.upload_app("build/MyApp.ipa")  # or target.upload_app(...) inside serve()
options.set_capability("appium:app", token)
# or later, inside a session:
driver.execute_script("mobile: installApp", {"app": token})

upload_app() accepts .apk, .aab, .apks, .ipa and .zip files and .app bundles, which it zips first. Uploads last until reset or the end of the lease.

Command line

Inside a jmp shell, with the child named appium:

j appium                                   # print url, ca_file and capabilities until Ctrl+C
j appium -- pytest tests/ui                # run a command with environment()
j appium upload build/MyApp.ipa            # print an application token
j appium stop

Security and limits

A lease holder controls the target through Appium, so the driver keeps Appium from reaching beyond it:

  • Appium binds exporter loopback, starts with every insecure feature denied and no plugins, and gets a private HOME.

  • Capabilities the target driver fixes replace any value a client sends.

  • Capabilities whose string values name files, directories, executables or URLs (for example appium:chromedriverExecutable or appium:mjpegScreenshotUrl), the proxy capability and any remotePath argument are rejected, so clients cannot make the exporter read its files or contact other hosts.

  • app, otherApps and appPath accept only tokens from upload_app().

Appium runs as a child process of the exporter, in the exporter’s container, so the rules above, not a container boundary, are what keep a lease to its device. Keep exporter images to what the targets need, and reset or re-provision devices between untrusted tenants. See Appium UI Automation for an overview of every target.

API Reference

class jumpstarter_driver_appium.driver.AppiumDriver

Run an operator-installed Appium on the exporter for one lease.

Appium listens on exporter loopback only and is reached through the lease over verified HTTPS. Target drivers subclass it to add the capabilities they fix at runtime, or configure capabilities directly.

class jumpstarter_driver_appium.client.AppiumClient

Open Appium sessions on a leased target, wherever its driver runs Appium.

info() → dict

Start the target’s Appium if needed and describe it.

serve(*, port: int = 0) → Generator[AppiumTarget, None, None]

Expose the target’s Appium on a loopback HTTPS port for the length of the block.

port=0 picks an unused port. Closing the block removes the listener and the CA file; the exporter keeps Appium running until stop(), power off, reset or the end of the lease.

stop() → None

Stop the target’s Appium; the next session starts a fresh one.

upload_app(path: str | PathLike) → str

Upload an application for this lease and return the token to use as appium:app.

Accepts .apk, .aab, .apks, .ipa and .zip files and .app bundles, which are zipped first. The token also works as the app argument of mobile: installApp. Uploads last until reset or the end of the lease.

class jumpstarter_driver_appium.common.AppiumTarget

An Appium server for one leased target, valid inside its context.

Open WebDriver sessions on url with capabilities(), and give applications from upload_app() as appium:app. Where Appium runs is the driver’s choice: on the exporter, reached over the lease, or on this machine for targets only it can reach. Sessions behave the same either way.

capabilities() → dict[str, Any]

W3C capabilities for a session on this target; add your own before use.

client_config(**kwargs)

An Appium-Python-Client AppiumClientConfig that trusts this target.

Needs the Appium-Python-Client package, which Jumpstarter does not install.

environment(base: Mapping[str, str] | None = None) → dict[str, str]

Copy the environment and describe this target to a tool in another language.

Adds JUMPSTARTER_APPIUM_URL, JUMPSTARTER_APPIUM_CAPABILITIES (JSON) and, for HTTPS targets, JUMPSTARTER_APPIUM_CA_FILE and Node’s NODE_EXTRA_CA_CERTS. Certificate verification stays enabled.

ssl_context() → SSLContext | None

Python’s normal trust plus this target’s CA, or None for plain HTTP.

upload_app(path: str | PathLike) → str

Make an application available to this target; returns the token to use as appium:app.

The token also works as the app argument of mobile: installApp.

Targets that only the client can reach, such as an iOS device shown through Device Hub, run the user’s installed Appium on the client instead and yield the same AppiumTarget. They put the same policy in front of it, so sessions accept the same capabilities and upload_app() tokens as on the exporter:

jumpstarter_driver_appium.local.local_appium(executable: str = 'appium', *, env: Mapping[str, str] | None = None, timeout: float = 60.0) → Generator[str, None, None]

Run the user’s installed Appium on a loopback port and yield its URL.

Appium uses the caller’s environment, so its APPIUM_HOME and installed drivers apply. It stops when the context closes.