Feature-rich Android device automation via ADB
Project description
adbflow
Async-first, type-safe Python package for Android device automation via ADB.
adbflow gives you a clean, modern Python API for everything you'd do with adb — UI automation, gestures, app management, file operations, screen capture, and much more. Built on asyncio with full type hints.
Documentation · PyPI · GitHub
Features
- Async-first — every operation is
async/awaitwith sync wrappers available - Type-safe — full type hints, passes
mypy --strict - UI automation — find elements by text/ID/class, tap, type, wait for conditions
- Gestures — tap, swipe, drag, pinch, multi-touch
- App management — install, launch, stop, permissions, intents
- File operations — push, pull, ls, sync directories with checksum diffing
- Screen capture — screenshots (bytes, PIL, file), screen recording
- Wait engine — composable conditions with
AllOf,AnyOf,Not - Vision — template matching and color detection (optional: opencv)
- OCR — on-screen text recognition (optional: easyocr)
- Watchers — auto-dismiss dialogs, background UI monitors
- Recorder — record and replay action sequences
- Flow engine — multi-step workflows with conditions and retry logic
- Multi-device — parallel execution across device pools
- Logcat — stream, filter, and capture logs
- Network — WiFi, mobile data, airplane mode, port forwarding, proxy
- Notifications — list, find, wait for notifications
- CLI —
adbflowcommand for common operations
Installation
pip install adbflow
Optional extras
pip install adbflow[vision] # Template matching, color detection (opencv)
pip install adbflow[ocr] # Text recognition (EasyOCR)
pip install adbflow[all] # Everything
Requirements
- Python 3.10+
- ADB installed and on
PATH(Android Platform-Tools) - An Android device with USB Debugging enabled
Quick Start
import asyncio
from adbflow import ADB
async def main():
adb = ADB()
device = await adb.device_async()
# Device info
model = await device.info.model_async()
print(f"Connected to {model}")
# Shell commands
output = await device.shell_async("getprop ro.product.model")
# UI automation
from adbflow.ui import Selector
element = await device.ui.find_async(
Selector().text("Settings").clickable()
)
if element:
await element.tap_async()
# Wait for UI state
await device.wait_for_text_async("Display", timeout=5.0)
# Gestures
from adbflow.utils.types import SwipeDirection
await device.gestures.swipe_direction_async(SwipeDirection.UP)
# Screenshots
png_bytes = await device.screenshot_async()
# App management
await device.apps.start_async("com.example.app")
await device.apps.stop_async("com.example.app")
asyncio.run(main())
Sync API
Every _async method has a sync wrapper for scripts that don't need asyncio:
from adbflow import ADB
adb = ADB()
device = adb.device()
output = device.shell("getprop ro.product.model")
print(output)
Modules
| Module | Access | Description |
|---|---|---|
| UI | device.ui |
Find elements, tap, type, wait |
| Gestures | device.gestures |
Tap, swipe, drag, pinch, keys |
| Apps | device.apps |
Install, launch, stop, permissions, intents |
| Files | device.files |
Push, pull, ls, sync, backup |
| Media | device.media |
Screenshots, screen recording, audio |
| Network | device.network |
WiFi, mobile data, airplane, port forwarding |
| Logcat | device.logcat |
Stream, filter, capture, crash detection |
| Notifications | device.notifications |
List, find, wait for notifications |
| Wait | device.wait_for_text_async() |
Composable wait conditions |
| Vision | device.vision |
Template matching, color detection |
| OCR | device.ocr |
Text recognition via EasyOCR |
| Watchers | device.watchers |
Auto-dismiss dialogs |
| Recorder | device.recorder |
Record and replay actions |
| Parallel | DevicePool |
Multi-device execution |
| Flow | Flow |
Multi-step workflow engine |
Examples
UI Automation
from adbflow.ui import Selector
# Find and tap
button = await device.ui.find_async(
Selector().resource_id("com.example:id/submit").clickable()
)
await button.tap_async()
# Wait for element
element = await device.ui.wait_for_async(
Selector().text("Welcome"), timeout=10.0
)
# Type text
field = await device.ui.find_async(
Selector().resource_id("com.example:id/search")
)
await field.tap_async()
await field.text_input_async("hello world")
Wait Conditions
from adbflow.wait import wait_for, TextVisible, any_of, not_
# Wait for success or error
await wait_for(
any_of(TextVisible(device, "Success"), TextVisible(device, "Error")),
timeout=10.0
)
# Wait for loading to disappear
await wait_for(not_(TextVisible(device, "Loading...")), timeout=15.0)
Multi-Device
from adbflow.parallel import DevicePool
pool = DevicePool(devices)
async def screenshot_all(device):
model = await device.info.model_async()
await device.media.screenshot.capture_to_file_async(f"{model}.png")
results = await pool.run_async(screenshot_all)
Flow Engine
from adbflow.flow import Flow
from adbflow.utils.types import ErrorStrategy
flow = Flow(device)
flow.add_step("open", open_app)
flow.add_step("login", login, retries=2)
flow.add_step("verify", verify, on_error=ErrorStrategy.SKIP)
result = await flow.run_async()
CLI
adbflow devices # List connected devices
adbflow shell "ls /sdcard" # Run shell command
adbflow screenshot out.png # Take screenshot
adbflow install app.apk # Install APK
adbflow info # Device info
adbflow logcat # Stream logs
adbflow record -o rec.json # Record actions
adbflow play rec.json # Replay actions
Documentation
Full documentation is available at shahadh7.github.io/adbflow.
Contributing
git clone https://github.com/Shahadh7/adbflow.git
cd adbflow
python -m venv .venv && source .venv/bin/activate
pip install -e ".[all,dev]"
pytest # Run tests
ruff check src/ # Lint
mypy src/adbflow/ # Type check
See the Contributing guide for details.
License
MIT — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adbflow-0.2.0.tar.gz.
File metadata
- Download URL: adbflow-0.2.0.tar.gz
- Upload date:
- Size: 135.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17361c253bd6dbdb9ac950824a6696fa6f5ab555167f88b7ba702ded34f6755e
|
|
| MD5 |
96b1eb2cee790210989f4dd0a2153e0c
|
|
| BLAKE2b-256 |
fe37b465eed539a5b924396e0a7153dbf90a84ea0b4445e8604f3caf9b59faa2
|
Provenance
The following attestation bundles were made for adbflow-0.2.0.tar.gz:
Publisher:
publish.yml on Shahadh7/adbflow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
adbflow-0.2.0.tar.gz -
Subject digest:
17361c253bd6dbdb9ac950824a6696fa6f5ab555167f88b7ba702ded34f6755e - Sigstore transparency entry: 1776675540
- Sigstore integration time:
-
Permalink:
Shahadh7/adbflow@c1afac3495ee91e2048e99b310e96faa6e623fea -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Shahadh7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c1afac3495ee91e2048e99b310e96faa6e623fea -
Trigger Event:
release
-
Statement type:
File details
Details for the file adbflow-0.2.0-py3-none-any.whl.
File metadata
- Download URL: adbflow-0.2.0-py3-none-any.whl
- Upload date:
- Size: 85.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f959306cb55f1e03fd0e31cb89d00a22077e2c804b3771b302fc9ee53f4ed317
|
|
| MD5 |
334a627e166da5ff14681c88bda7009b
|
|
| BLAKE2b-256 |
dbce320e27b3932eb02518789fd525426bc12b526efbadfa8fe02ffef3fa97a9
|
Provenance
The following attestation bundles were made for adbflow-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on Shahadh7/adbflow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
adbflow-0.2.0-py3-none-any.whl -
Subject digest:
f959306cb55f1e03fd0e31cb89d00a22077e2c804b3771b302fc9ee53f4ed317 - Sigstore transparency entry: 1776675629
- Sigstore integration time:
-
Permalink:
Shahadh7/adbflow@c1afac3495ee91e2048e99b310e96faa6e623fea -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Shahadh7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c1afac3495ee91e2048e99b310e96faa6e623fea -
Trigger Event:
release
-
Statement type: