droidrun-rs
Pure Rust implementation of Android device automation — a rewrite of the droidrun Python framework's android-driver and portal-controller layers.
Fully async with tokio. Zero Python dependencies.
Features
- Async ADB client — Native ADB wire protocol + sync protocol over TCP, no
adbCLI dependency - 70+ ADB operations — Shell, file sync (push/pull/stat/list), port forwarding, reverse forwarding, app management, device info, screen control, logcat streaming
- Portal integration — Dual-mode communication (TCP + ContentProvider fallback)
- UI state pipeline — Accessibility tree filtering, formatting, and element resolution
- Recording driver — Proxy wrapper that logs all actions as JSON
- CLI tool — Full-featured command-line interface for device automation
- 120+ tests — Unit tests (83) + integration tests (37) + doc tests (2)
Installation
Prerequisites
- Rust 1.85.0+
- ADB server running (
adb start-server) - Android device/emulator with DroidRun Portal installed
Build from source
The CLI binary will be at target/release/droidrun.
Quick Start
CLI
# List connected devices
# Check device + Portal health
# Take a screenshot
# Tap at coordinates
# Type text
# Get UI state (formatted)
# Get UI state (raw JSON)
# Swipe down
# Open an app
# Run a shell command
As a library
Cargo.toml:
[]
= { = "crates/droidrun-core" }
= { = "1", = ["full"] }
Basic usage:
use AndroidDriver;
use DeviceDriver;
async
Using the state provider pipeline:
use ;
use ;
async
Low-level ADB operations:
use AdbServer;
use Path;
async
Recording driver:
use ;
async
Architecture
┌──────────────┐
│ droidrun-cli │ CLI tool (clap subcommands)
└──────┬───────┘
│
┌──────▼────────┐
│ droidrun-core │ DeviceDriver trait, Portal client, UI pipeline
└──────┬────────┘
│
┌──────▼───────┐
│ droidrun-adb │ Async ADB wire protocol over TCP
└──────────────┘
Crates
| Crate | Description |
|---|---|
| droidrun-adb | Low-level async ADB client. Implements ADB wire protocol + sync protocol over TCP using tokio. 70+ methods covering: device discovery, shell (with exit codes), file sync (push/pull/stat/list), port forwarding & reverse forwarding, screenshots, input control, app management, device properties, screen info, and logcat streaming. |
| droidrun-core | High-level automation framework. Defines the DeviceDriver trait, Portal APK management, dual-mode Portal communication (TCP + ContentProvider), and the UI state processing pipeline (filter → format → UIState). |
| droidrun-cli | Command-line tool built with clap. Exposes all framework capabilities as subcommands. |
Portal Communication
DroidRun Portal is an Android APK that provides accessibility tree access, keyboard input, and screenshot capabilities. The framework communicates with Portal via two transport modes:
| Mode | How | Speed | Use case |
|---|---|---|---|
| TCP | HTTP requests to Portal's embedded server (port 8080, ADB-forwarded) | Fast | Default, preferred |
| ContentProvider | adb shell content query/insert commands |
Slower | Automatic fallback |
The client automatically falls back from TCP to ContentProvider on failure.
UI State Pipeline
Raw accessibility tree (JSON from Portal)
↓
TreeFilter (ConciseFilter) — removes off-screen & tiny elements
↓
TreeFormatter (IndexedFormatter) — assigns indices, formats text
↓
UIState {
elements: Vec<Element>, // flattened with indices
formatted_text: String, // human-readable output
phone_state: PhoneState, // current app, keyboard, focus
screen: ScreenDimensions, // width x height
}
Both TreeFilter and TreeFormatter are traits — implement your own for
custom processing.
CLI Reference
droidrun [OPTIONS] <COMMAND>
Options:
-s, --serial <SERIAL> Device serial number
--tcp Use TCP mode (default: true)
-v, --verbose Enable debug logging
Commands:
devices List connected devices
setup Install & configure Portal on device
doctor Check device + Portal health
screenshot Take a screenshot [default: screenshot.png]
tap Tap at coordinates (x, y)
swipe Swipe between points (x1, y1, x2, y2) [--duration ms]
type Type text into focused field [--clear]
key Send key event (3=Home, 4=Back, 66=Enter)
state Get UI state [--json]
apps List installed apps [--system]
open Start an app by package name [--activity name]
shell Run a shell command on device
Examples
14 runnable examples across both library crates:
# droidrun-adb examples (8)
# droidrun-core examples (6)
Testing
122 tests total (83 unit + 37 integration + 2 doc):
# All tests (needs device connected)
# Unit tests only (no device needed)
# Integration tests
# Skip device tests
SKIP_DEVICE_TESTS=1
Test Requirements
- ADB server running
- Android emulator or device connected
- DroidRun Portal APK installed with accessibility service enabled (for droidrun-core tests)
Dependencies
| Crate | Purpose |
|---|---|
| tokio | Async runtime |
| reqwest | HTTP client for Portal TCP |
| serde | JSON serialization |
| clap | CLI argument parsing |
| thiserror | Error derive macros |
| tracing | Structured logging |
| async-trait | Async trait support |
| base64 | Encoding for keyboard/screenshots |
License
MIT