Android automation made simple - record, replay, and control Android devices
Project description
DittoMation
Android automation framework that records touch interactions, maps them to UI elements, and replays them using smart element location. Supports natural language commands for intuitive automation.
Features
- Record touch gestures (tap, swipe, long press, scroll, pinch) from Android device
- Replay recorded workflows with smart element location
- Natural Language command execution - describe actions in plain English
- Smart Locators - fallback chain (resource-id → content-desc → text → xpath → coordinates)
- Intent-based App Launching - reliable app opening via Android intents
- Variables & Expressions - dynamic scripts with
{{variable}}syntax and safe expression evaluation - Control Flow - if/else conditions, for/while/until loops for complex automation
Requirements
- Python 3.8+
- Android SDK with ADB (Android Debug Bridge)
- Android device/emulator with USB debugging enabled
Installation
From PyPI (Recommended)
pip install dittomation
With optional cloud provider support:
pip install dittomation[aws] # AWS Device Farm
pip install dittomation[firebase] # Firebase Test Lab
pip install dittomation[all] # All extras
From Source
- Clone the repository:
git clone https://github.com/OmPrakashSingh1704/DittoMation.git
cd DittoMation
- Install the package:
pip install -e .
For development:
pip install -e .[dev]
Verify Installation
Ensure ADB is accessible:
adb devices # Should show your connected device
Project Structure
DittoMation/
├── recorder/
│ ├── adb_wrapper.py # ADB command utilities
│ ├── event_listener.py # Touch event capture via getevent
│ ├── ui_dumper.py # UI hierarchy capture & parsing
│ ├── element_matcher.py # Coordinate to element mapping
│ ├── gesture_classifier.py # Gesture recognition (tap/swipe/etc)
│ ├── workflow.py # Workflow storage & management
│ ├── main.py # Recording CLI
│ └── interactive_recorder.py # Manual step-by-step recording
├── replayer/
│ ├── locator.py # Smart element location
│ ├── executor.py # Gesture execution via ADB
│ ├── main.py # Replay CLI
│ ├── text_runner.py # Plain text command execution
│ └── nl_runner.py # Natural language execution
├── docs/
│ └── approach.md # Technical approach documentation
├── output/ # Generated workflow files
└── README.md
Usage
Natural Language Runner (Recommended)
Execute Android actions using natural language:
# Single command
python replayer/nl_runner.py "Open YouTube, search for 'Mr. Beast', play latest video"
# Interactive mode
python replayer/nl_runner.py --interactive
# From file
python replayer/nl_runner.py --file instructions.txt
Supported Commands:
open [app]- Open an app (Clock, YouTube, Settings, etc.)tap [element]- Tap on element by text/descriptionlong press [element]- Long press on elementswipe up/down/left/right- Swipe gesturesscroll up/down- Scroll gesturestype "text"- Input textsearch for "query"- Search within current appback/home- Navigationwait [seconds]- Pause executioncall [number]- Make a phone callset alarm for 8:00- Set an alarmgo to [url]- Open URL in browserplay first/latest video- Play video resultscopy last number I called- Copy to clipboardsearch for that number you copied- Use clipboard
Recording Workflows
# Interactive recording (recommended for emulators)
python recorder/interactive_recorder.py --output my_workflow.json
# Automated recording via getevent (physical devices)
python recorder/main.py --output my_workflow.json
Replaying Workflows
# Replay a recorded workflow
python replayer/main.py --workflow my_workflow.json
# With custom delay between steps
python replayer/main.py --workflow my_workflow.json --delay 1000
Scripted Automation with Variables
Run automation scripts with variables and control flow:
# Basic script execution
ditto run script.json
# With command-line variables
ditto run login.json --var username=myuser --var password=secret
# With variables file
ditto run script.json --vars-file config.json --verbose
Example script with variables and conditions (login.json):
{
"name": "smart_login",
"variables": {
"username": "testuser",
"max_retries": 3
},
"steps": [
{"action": "open", "app": "MyApp"},
{
"action": "if",
"expr": "element_exists(text='Welcome')",
"then_steps": [
{"action": "log", "message": "Already logged in"}
],
"else_steps": [
{"action": "tap", "text": "Login"},
{"action": "type", "value": "{{username}}"},
{"action": "tap", "text": "Submit"}
]
}
]
}
See Variables and Control Flow Guide for complete documentation.
Text-based Commands
# Simple text commands
python replayer/text_runner.py "tap Phone; tap Contacts; swipe down"
# From file
python replayer/text_runner.py commands.txt
Examples
Open YouTube and Play a Video
python replayer/nl_runner.py "Open YouTube, search for 'cooking tutorial', play first video"
Make a Phone Call
python replayer/nl_runner.py "Call 1234567890, wait 30, end call"
Set an Alarm
python replayer/nl_runner.py "Open clock, set alarm for 7:30 am"
Copy and Search
python replayer/nl_runner.py "Open phone, copy last number I called, go home, open youtube, search for that number you copied"
How It Works
See docs/approach.md for detailed technical documentation.
Troubleshooting
ADB not found
Set the ANDROID_HOME environment variable or add ADB to your PATH.
UI dump timeout
The device may be busy. The tool will retry automatically. You can also:
adb shell pkill -f uiautomator
Text input drops characters
This can happen on slow devices. The tool types in chunks with delays to mitigate this.
App not found
Use the exact app name as it appears on the device, or use one of the supported intent-based apps (clock, settings, youtube, etc.).
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
This project is licensed under the MIT License - see the LICENSE file 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 dittomation-1.0.0.tar.gz.
File metadata
- Download URL: dittomation-1.0.0.tar.gz
- Upload date:
- Size: 160.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f3bca32c5fc4275dab5bfdc3112638158095c9a97a182c6ea38c155949cb130
|
|
| MD5 |
22ecc4126dcb2a282b82ada41cca5a84
|
|
| BLAKE2b-256 |
d022902f44a6f984da94e9eff2f29880b4752c8ea19876b55ddbcff6e7f4f837
|
Provenance
The following attestation bundles were made for dittomation-1.0.0.tar.gz:
Publisher:
release.yml on OmPrakashSingh1704/DittoMation
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dittomation-1.0.0.tar.gz -
Subject digest:
6f3bca32c5fc4275dab5bfdc3112638158095c9a97a182c6ea38c155949cb130 - Sigstore transparency entry: 854740315
- Sigstore integration time:
-
Permalink:
OmPrakashSingh1704/DittoMation@3d47d85e78591f545138bcb6d54d84722401e9c7 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/OmPrakashSingh1704
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3d47d85e78591f545138bcb6d54d84722401e9c7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dittomation-1.0.0-py3-none-any.whl.
File metadata
- Download URL: dittomation-1.0.0-py3-none-any.whl
- Upload date:
- Size: 149.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a53fd9749225e21c645ef7dbb647e942c443e867e9b7b15e80f77e054d3a6318
|
|
| MD5 |
f7aaafa12aec7fc07af60116cd9731f6
|
|
| BLAKE2b-256 |
b217a4e83b3cb8fb381f169fb16acb28aa17e3d8c8187f6fee21ef3582f853ae
|
Provenance
The following attestation bundles were made for dittomation-1.0.0-py3-none-any.whl:
Publisher:
release.yml on OmPrakashSingh1704/DittoMation
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dittomation-1.0.0-py3-none-any.whl -
Subject digest:
a53fd9749225e21c645ef7dbb647e942c443e867e9b7b15e80f77e054d3a6318 - Sigstore transparency entry: 854740318
- Sigstore integration time:
-
Permalink:
OmPrakashSingh1704/DittoMation@3d47d85e78591f545138bcb6d54d84722401e9c7 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/OmPrakashSingh1704
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3d47d85e78591f545138bcb6d54d84722401e9c7 -
Trigger Event:
release
-
Statement type: