Skip to main content

mobilerun-core-local is the slim async local-driver core of mobilerun.
No CLI, no agent, no LLM providers — just local Android/iOS drivers for higher-level tools such as mobilerun-core.


  • 📱 Drive local devices — Android over ADB with optional Portal, Android Portal HTTP-only, or iOS Portal HTTP.
  • ⚡ TCP-with-content-provider fallback — fast Android HTTP path over adb forward, transparent fallback to content-provider RPC.
  • 🔌 HTTP-only drivers — connect to already-running Android/iOS portals without taking over setup.
  • 🛠 Portal lifecycle — download, install, accessibility enablement, auto-upgrade.
  • 🪶 Slim — a small async driver package with four runtime deps (async_adbutils, httpx, requests, rich).
  • 🔌 Embeddable — designed to be wrapped by sync facades (e.g. mobilerun-core) or used directly.
  • 🤝 In sync with upstream — verbatim slice of droidrun/mobilerun; behaviour and API track upstream.

📦 Installation

Note: Python >=3.11,<3.14. The Android ADB driver requires ADB on PATH and a device with USB debugging enabled. HTTP-only drivers require an already-running portal URL.

uv pip install mobilerun-core-local

🚀 Quick usage

import asyncio
from async_adbutils import adb
from mobilerun_core_local import AndroidDriver
from mobilerun_core_local.driver.android import ensure_portal_ready


async def main():
    # 1. Optional: make sure Portal is installed + accessibility is on for
    #    Portal-enhanced state/text paths. AndroidDriver still works over ADB
    #    without this step.
    device = await adb.device()
    await ensure_portal_ready(device)

    # 2. Drive the device.
    driver = AndroidDriver(serial=device.serial, use_tcp=True)
    await driver.connect()

    await driver.tap(540, 1200)
    await driver.swipe(540, 1600, 540, 400, duration_ms=300)
    await driver.input_text("hello", clear=True)
    png_bytes = await driver.screenshot()
    tree = await driver.get_ui_tree()


asyncio.run(main())

HTTP-only Android:

import asyncio
from mobilerun_core_local import AndroidPortalHttpDriver


async def main():
    driver = AndroidPortalHttpDriver(
        url="http://127.0.0.1:18080",
        token="...",
    )
    await driver.connect()
    await driver.tap(540, 1200)


asyncio.run(main())

iOS with mobilerun-ios --local:

Follow the Connect an iPhone guide to set up and start the iOS portal.

import asyncio
from mobilerun_core_local import IOSPortalHttpDriver


async def main():
    driver = IOSPortalHttpDriver("http://127.0.0.1:8080")
    await driver.connect()
    await driver.start_app("com.apple.Preferences")


asyncio.run(main())

🧱 Layout

Platform-specific code is namespaced under driver/<platform>/ and transport/<platform>/. Adding a new backend (e.g. iOS over USB, a new Android transport) does not pollute the package root.

mobilerun_core_local/
├── __init__.py                       Re-exports the public driver surface
├── driver/
│   ├── base.py                       DeviceDriver ABC, DeviceDisconnectedError
│   ├── android/
│   │   ├── adb.py                    AndroidDriver — ADB-backed driver
│   │   ├── http.py                   AndroidPortalHttpDriver — HTTP-only driver
│   │   └── portal.py                 Portal APK lifecycle + content-provider helpers
│   └── ios/
│       └── http.py                   IOSPortalDriver — ios-portal HTTP driver
└── transport/
    └── android/
        └── portal_client.py          PortalClient — TCP-with-content-provider fallback

📚 Public API

Re-exported from mobilerun_core_local:

Symbol What it is
AndroidDriver ADB-first Android driver with optional Portal enhancement. Async methods: tap, swipe, input_text, press_button, start_app, install_app, screenshot, get_ui_tree, get_apps, list_packages, get_date.
AndroidPortalHttpDriver HTTP-only Android Portal driver. Requires url and bearer token; does not use ADB at runtime.
IOSPortalDriver / IOSDriver iOS Portal HTTP driver. Requires an already-running ios-portal URL.
DeviceDriver Abstract base for drivers. supported: set[str] declares which verbs a subclass implements.
DeviceDisconnectedError Raised when the device drops mid-call.
validate_android_portal_url(url) / validate_ios_portal_url(url) Normalize + sanity-check portal URLs.
discover_ios_portal(...) Scan localhost for a reachable ios-portal HTTP endpoint.

Android Portal helpers live under mobilerun_core_local.driver.android (not at the package root, since they're Android-specific):

Symbol What it is
setup_portal(device, debug=False, *, version=None, uninstall=True) Download + install + enable the Portal APK on a device. With version (your package version), installs the Portal pinned for it in the version map; without it, or when the map has no entry or can't be fetched, installs the latest release. uninstall=True clears Portal's settings first; uninstall=False updates in place unless the installed APK has a different signature or a higher version code, which Android only allows after an uninstall.
ensure_portal_ready(device, debug=False, *, version=None) Idempotent: install Portal and enable accessibility if needed. With version, also upgrades an installed Portal that is older than the pin, in place; a newer Portal is kept, and a failed upgrade keeps the installed one.
setup_keyboard(device) Switch the device to the Mobilerun IME.
ping_portal(device) Verify Portal is installed and reachable.
PORTAL_PACKAGE_NAME, A11Y_SERVICE_NAME Portal identifiers.
portal_content_uri(pkg, path) Build content://<pkg>/<path> URIs.
portal_a11y_service(pkg), portal_ime_id(pkg) Accessibility service / IME component names.

PortalClient (the TCP-with-content-provider transport) lives at mobilerun_core_local.transport.android.PortalClient — used internally by AndroidDriver, exposed for low-level access.

AndroidDriver accepts:

  • serial: str | None — ADB serial; None picks the only connected device.
  • use_tcp: bool = False — when True, the underlying PortalClient port-forwards Portal's HTTP server (localhost:N → device:8080) and uses it instead of the content provider. Faster but requires a working forward; falls back transparently.

🪵 Logging

All output goes through the "mobilerun_core_local" logger. Configure it yourself; the package attaches no handlers.

import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("mobilerun_core_local").setLevel(logging.DEBUG)

🔗 Relationship to upstream mobilerun

This package owns local execution drivers. The full framework imports these drivers for CLI/agent flows; mobilerun-core wraps them behind a sync, backend-neutral API.

Use mobilerun-core-local when you need async local drivers directly. Use mobilerun when you want the full LLM-agent experience, CLI/TUI, and multi-platform support out of the box.

📄 License

MIT — see LICENSE.

Metadata

Release files for mobilerun-core-local 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mobilerun-core-local 0.6.1
File Size Uploaded
mobilerun_core_local-0.6.1.tar.gz 77.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mobilerun-core-local 0.6.1
File Interpreter ABI Platform
mobilerun_core_local-0.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 129.3 kB

Release files / mobilerun_core_local-0.6.1.tar.gz

Download URL mobilerun_core_local-0.6.1.tar.gz
Size 77.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e27becfc1cfb12b99bf82d1daad89b975c0e4e16923a318e26dfe472abd2c8ec
BLAKE2b-256 checksum
How to use checksums
65a3b34fbdaecd51c0aafe5eb4eda661c442105eb6ffedc26f7a897e508b5b9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / mobilerun_core_local-0.6.1-py3-none-any.whl

Download URL mobilerun_core_local-0.6.1-py3-none-any.whl
Size 52.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a3a7948dfece3bdabb73c5aa6bf93eb8a020da3d0cd85ddac1b7310a70cfcc34
BLAKE2b-256 checksum
How to use checksums
b87738337b2088d32a6b3cd26d756ba42321a55dc013bb59aa1a0f338ad64a63
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.2

2 release files

This release

0.6.1 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page