Skip to main content

The Python client

It speaks to the same tool layer as the CLI and the MCP server, by spawning mobium pipe, so the mobium binary has to be on PATH or named by MOBIUM_BIN_PATH. The quick start goes from nothing to a running script.

Install​

pip install "mobium @ git+https://github.com/mobiumdev/mobium.git#subdirectory=clients/python"

Connect​

from mobium import start

with start(platform="android", app="com.android.settings") as device:
for el in device.map():
print(el.ref, el.label)

device below is what start() or connect() returned: a mobium.Device.

Every tool, by method​

MethodTool
accessibilityapp_accessibility
alert, answer_alertapp_alert
appearanceapp_appearance
auditapp_audit
backgroundapp_background
batchapp_batch
batteryapp_battery
biometricapp_biometric
bootapp_boot
incoming_callapp_call
checkapp_check
clear_dataapp_clear_data
clipboard, set_clipboardapp_clipboard
contextapp_context
contextsapp_contexts
clear_cookies, cookies, set_cookiesapp_cookies
crash, crashesapp_crashes
currentapp_current
devicesapp_devices
add_dialog_rule, clear_dialog_rules, dialog_rulesapp_dialogs
doctorapp_doctor
download, downloads, pull_pathapp_download
dragapp_drag
evalapp_eval
fillapp_fill
findapp_find
grantapp_grant
hit_testapp_hit_test
hookapp_hook
installapp_install
keyboardapp_keyboard
launchapp_launch
appsapp_list_apps
app_locale, set_app_localeapp_locale
clear_location, follow_gpx, follow_route, location, set_locationapp_location
screen_locked, set_screen_lockedapp_lock
device_logs, logsapp_logs
long_pressapp_long_press
map, map_diffapp_map
network, reset_network, set_offline, shape_networkapp_network
notifications, post_notification, shadeapp_notifications
open_urlapp_open_url
orientation, set_orientationapp_orientation
back, pressapp_press
press_dragapp_press_drag
press_tapapp_press_tap
recordapp_record
reset_permissionsapp_reset_permissions
revokeapp_revoke
rotateapp_rotate
screenapp_screen
screenshotapp_screenshot
scroll_toapp_scroll_to
quit, sessions, startapp_session
shakeapp_shake
shutdownapp_shutdown
smsapp_sms
sourceapp_source
app_stateapp_state
clear_storage, set_storage, storageapp_storage
swipeapp_swipe
double_tap, tapapp_tap
terminateapp_terminate
textapp_text
device_timeapp_time
timezoneapp_timezone
trace, trace_start, trace_stopapp_trace
typeapp_type
uninstallapp_uninstall
push_path, uploadapp_upload
wait_forapp_wait_for
zoomapp_zoom

Connecting, ending, and errors​

connect​

def connect(device: str | None=None, driver: str | None=None, binary: str | None=None, call_timeout: float | None=None, session: str | None=None) -> 'Device'

Start a mobium session.

device: serial or UDID, when more than one is running. driver: "uiautomator2" (default), "uiautomator", or "wda". call_timeout: the longest, in seconds, any one call may take before the connection is given up, the handshake included. None, the default, waits as long as it takes: the first session on an iPhone builds WebDriverAgent, which takes minutes. A call that runs out ends the connection -- a late answer would be read as the next call's -- and every call after raises, saying so; connect again. Set it well above the longest wait_for timeout you use. session: a daemon of this connection's own, by name, as MOBIUM_SESSION sets one. One daemon serves one call at a time across every device, so parallel runs on different devices should each name one: sharing, an emulator's calls waited behind a simulator's, 22.3s against 0.3s. Keep it short; it is part of a socket path.

Connect without opening a session first

import mobium

device = mobium.connect()
print(device.current())
device.close()

Pick one of several devices, with a daemon of its own

from mobium import connect

device = connect(device="emulator-5554", session="pixel")

close​

def close() -> None
def close() -> None

Close the connection. The device's session lives in the daemon and stays open, for the next connect() or the CLI; quit() ends it.

Close the connection and leave the session open

device = mobium.connect()
try:
print(device.current())
finally:
device.close()

Device​

class Device

A connected device or simulator.

Use a device in a with block, which quits on the way out

with mobium.start(platform="android", app="com.android.settings") as device:
for el in device.map():
print(el.ref, el.label)

Element​

class Element

One actionable element on screen.

Read an element's fields

for el in device.map():
print(el.ref, el.label, el.role, el.locator, el.checked)

Bounds​

class Bounds

An on-screen rectangle in device pixels, on both platforms.

Find where an element is on screen

el = device.find("text=System")[0]
print(el.bounds.center, el.bounds.width, el.bounds.height)

DeviceInfo​

class DeviceInfo

One attached device or simulator.

Tell emulators from real hardware

for info in device.devices():
kind = "emulator" if info.emulator else "device"
print(info.id, info.model, kind)

Session​

class Session

What start() opened: the device and how it is driven.

See what start() opened

device = mobium.start(platform="ios")
print(device.session.device, device.session.driver, device.session.reused)

MobiumError​

class MobiumError(RuntimeError)

A tool reported that it could not do what was asked.

Also the exception for a code this client does not recognize, and for a daemon too old to send codes at all — code is then "error".

Catch any failure, and read its code and remedy

try:
device.tap("text=Continue")
except mobium.MobiumError as e:
print(e.code, e.message)
print(e.remedy)

NoSuchElementError​

class NoSuchElementError(MobiumError)

A locator or ref matched nothing on screen. Worth scrolling for.

Scroll for an element that is not on screen

from mobium import NoSuchElementError

try:
device.tap("text=Continue")
except NoSuchElementError:
device.scroll_to("text=Continue")

AmbiguousLocatorError​

class AmbiguousLocatorError(MobiumError)

A locator matched more than one element. Narrow it; Mobium never guesses.

Fall back to a ref when a locator matches more than one element

try:
device.tap("text=OK")
except mobium.AmbiguousLocatorError:
device.tap(device.find("text=OK")[0].ref)

TimedOutError​

class TimedOutError(MobiumError)

A wait ran out. Named TimedOut so it does not shadow the builtin TimeoutError.

Handle a wait that never came true

try:
device.wait_for("text=Welcome back", timeout_ms=5000)
except mobium.TimedOutError as e:
print("still not there:", e.message)

UnsupportedError​

class UnsupportedError(MobiumError)

This driver or platform cannot do it, and says why. Retrying cannot help.

Skip what a platform cannot do

try:
device.press("back")
except mobium.UnsupportedError:
device.tap("label=Back") # iOS has no back button

NoDeviceError​

class NoDeviceError(MobiumError)

Nothing to drive: no device matches, or none is connected.

Report that no device is running

try:
device = mobium.start()
except mobium.NoDeviceError as e:
print(e.remedy)

DeviceNotReadyError​

class DeviceNotReadyError(MobiumError)

The device is there and cannot be driven yet — locked, not trusted, Developer Mode off.

Unlock a device that is not ready

try:
device.launch("com.android.settings")
except mobium.DeviceNotReadyError:
device.set_screen_locked(False)
device.launch("com.android.settings")

NotConfirmedError​

class NotConfirmedError(MobiumError)

The command reported success and reading the state back disagreed.

Notice an action the device did not confirm

try:
device.timezone("Asia/Tokyo")
except mobium.NotConfirmedError as e:
print("not applied:", e.message)

NoSuchContextError​

class NoSuchContextError(MobiumError)

A WebView context that is not there.

Handle a WebView that is not there

try:
device.context("WEBVIEW_com.example.shop")
except mobium.NoSuchContextError:
print(device.contexts())

NoSuchAlertError​

class NoSuchAlertError(MobiumError)

A dialog was expected and none is on screen.

Answer a dialog only if one is up

try:
device.answer_alert(accept=False)
except mobium.NoSuchAlertError:
pass

ElementNotReachableError​

class ElementNotReachableError(MobiumError)

The element was found and cannot be touched where it is — usually off screen.

Handle an element that exists but cannot be touched

try:
device.tap("text=Buy")
except mobium.ElementNotReachableError as e:
print(e.details)

InvalidArgumentError​

class InvalidArgumentError(MobiumError)

The request itself is wrong.

Catch an argument the tool refused

try:
device.set_orientation("left")
except mobium.InvalidArgumentError as e:
print(e.message)

ToolchainMissingError​

class ToolchainMissingError(MobiumError)

Something on this machine is missing: adb, Xcode, a signing certificate.

Point at doctor when a tool is missing

try:
device = mobium.start(platform="ios")
except mobium.ToolchainMissingError as e:
print(e.remedy)

DeviceServerError​

class DeviceServerError(MobiumError)

The device side failed: a device server, or adb, simctl, devicectl, lockdown.

A device server's own W3C code, when it sent one, is in details["w3c"].

Read the device server's own code

try:
device.tap("@e2")
except mobium.DeviceServerError as e:
print(e.details.get("w3c"))

InternalError​

class InternalError(MobiumError)

A bug in Mobium.

Retry only what can succeed again

try:
device.map()
except mobium.InternalError as e:
if e.retryable:
device.map()

Types​

TypeWhat it is
BoundsAn on-screen rectangle in device pixels, on both platforms.
ElementOne actionable element on screen.
DeviceInfoOne attached device or simulator.
SessionWhat start() opened: the device and how it is driven.
DeviceA connected device or simulator.
MobiumErrorA tool reported that it could not do what was asked.
NoDeviceErrorNothing to drive: no device matches, or none is connected.
DeviceNotReadyErrorThe device is there and cannot be driven yet — locked, not trusted, Developer Mode off.
ToolchainMissingErrorSomething on this machine is missing: adb, Xcode, a signing certificate.
NoSuchElementErrorA locator or ref matched nothing on screen.
AmbiguousLocatorErrorA locator matched more than one element.
ElementNotReachableErrorThe element was found and cannot be touched where it is — usually off screen.
NoSuchContextErrorA WebView context that is not there.
NoSuchAlertErrorA dialog was expected and none is on screen.
UnsupportedErrorThis driver or platform cannot do it, and says why.
NotConfirmedErrorThe command reported success and reading the state back disagreed.
TimedOutErrorA wait ran out.
InvalidArgumentErrorThe request itself is wrong.
DeviceServerErrorThe device side failed: a device server, or adb, simctl, devicectl, lockdown.
InternalErrorA bug in Mobium.