🚀 AppPilot Mobile — The Master Guide
Welcome to the world-class documentation for AppPilot Mobile. This framework is designed to be the "Playwright for Mobile" — a Python-first, human-readable automation engine that handles the complexity of mobile UI so you can focus on writing tests.
🏗️ 1. Professional Architecture (POM)
AppPilot is optimized for the Page Object Model (POM). By following this structure, your tests will be readable, maintainable, and stable.
1.1 Screen Transition Example
In this model, the LoginScreen fills in credentials, taps submit, and then instantiates and returns the next screen (DashboardScreen):
class LoginScreen:
def login(self, username, password) -> DashboardScreen:
self.mobile.input("Username").fill(username)
self.mobile.input("Password").fill(password)
self.mobile.button("Login").tap()
return DashboardScreen(self.mobile)
1.2 Handling Elements Without Text Dynamically
You do not need separate methods (like tap_xpath() or tap_by_id()) for elements without text. The exact same public methods (mobile.tap(), mobile.fill(), etc.) handle all targets dynamically:
- Accessibility ID / Content Description:
mobile.tap("shopping_cart_icon") # Taps by accessibility label even if there is no text.
- Resource ID:
mobile.tap("com.example.app:id/submit_btn") # Identifies the developer-assigned element ID.
- Placeholder / Hint Text:
mobile.tap("Enter your password") # Text
- XPath Fallback:
mobile.tap("//android.widget.FrameLayout[1]/android.widget.Button[2]") # Triggers automatically if starting with "//".
🛠️ 2. Developer & Diagnostic Tools
2.1 Device Diagnostic (mobile.diagnose())
Provides a complete health check of the device and the automation environment.
- System Info: Model, Android version, and Serial.
- App State: Package and Activity currently in focus.
- Performance: Real-time Memory (MB) and CPU (%) usage.
- Usage:
mobile.diagnose()
📊 3. Complete API Reference
| Category | Method | Example | Description |
|---|---|---|---|
| Core | tap(target) / click() |
mobile.click("Login") |
Smart tap/click with auto-scroll. |
fill(target, text) / set_text() |
mobile.set_text("User", "admin") |
Locates label and fills input. | |
clear(target) / clear_text() |
mobile.clear_text("Search") |
Wipes text from a field. | |
double_tap(t) / double_click() |
mobile.double_click("Map") |
Rapid two-tap gesture. | |
long_press(target) |
mobile.long_press("File") |
1s touch-and-hold. | |
dropdown(target) |
mobile.dropdown("Theme").select(option="Dark") |
Opens dropdown and selects by option text or index. | |
| Diagnostics | inspect() |
mobile.inspect() |
Prints UI tree to console. |
diagnose() |
mobile.diagnose() |
Full device & app health check. | |
get_current_app() |
app = mobile.get_current_app() |
Returns package/activity. | |
get_performance() |
perf = mobile.get_performance() |
Returns CPU/Memory stats. | |
get_focused_element() |
active = mobile.get_focused_element() |
Gets properties of currently focused element. | |
get_active_element() |
active = mobile.get_active_element() |
Alias for get_focused_element(). | |
get_selected_element() |
active = mobile.get_selected_element() |
Alias for get_focused_element(). | |
| Device Mgmt | connect_device(serial) |
mobile.connect_device("192.168.1.5:5555") |
Connects via ADB TCP/IP. |
disconnect_device() |
mobile.disconnect_device() |
Disconnects device. | |
get_device_info() |
info = mobile.get_device_info() |
OS, Model, Manufacturer. | |
install_app(path) |
mobile.install_app("app.apk") |
Installs APK. | |
uninstall_app(pkg) |
mobile.uninstall_app("com.app") |
Uninstalls package. | |
close_app(pkg) |
mobile.close_app("com.app") |
Force stops application. | |
clear_app_data(pkg) |
mobile.clear_app_data("com.app") |
Resets app state. | |
grant_permissions() |
mobile.grant_permissions(pkg, ["camera"]) |
Auto-allow permissions. | |
set_location(lat, lon) |
mobile.set_location(12.9, 77.5) |
Spoofs GPS coordinates. | |
set_orientation(mode) |
mobile.set_orientation("landscape") |
Portrait/Landscape switch. | |
| Keyboard | send_keys(text) |
mobile.send_keys("Hello") |
Direct text to focused field. |
hide_keyboard() |
mobile.hide_keyboard() |
Dismisses soft keyboard. | |
show_keyboard() |
mobile.show_keyboard() |
Forces keyboard to open. | |
press_key(key) |
mobile.press_key("ENTER") |
Hardware key (BACK, HOME, etc). | |
| Gestures | swipe(x1,y1,x2,y2) |
mobile.swipe(100,500,900,500) |
Raw coordinate movement. |
scroll_to_text(text) |
mobile.scroll_to_text("Accept") |
Scrolls until text found. | |
drag_and_drop(s, t) |
mobile.drag_and_drop("App", "Bin") |
Moves element. | |
flick(x1,y1,x2,y2) |
mobile.flick(500,800,500,200) |
Fast swipe gesture. | |
| Discovery | get_page_source() |
xml = mobile.get_page_source() |
Returns UI hierarchy XML. |
get_all_texts() |
mobile.get_all_texts_displayed() |
Returns all visible strings. | |
get_text(target) |
mobile.get_text("Title") |
Reads text from element. | |
get_element_attributes(t) |
attrs = mobile.get_element_attributes("Btn") |
Gets detailed layout, state, and visual properties. | |
get_attributes() |
attrs = mobile.element("Btn").get_attributes() |
Chained attributes retriever for elements. | |
| Media | take_screenshot(n) |
mobile.take_screenshot("err") |
Captures full screen. |
capture_element(t,n) |
mobile.capture_element_screenshot("Btn","c") |
Crops to element bounds. | |
start_recording() |
mobile.start_screen_recording() |
Captures MP4 video. | |
capture_photo() |
mobile.capture_photo() |
Shutter + Auto-OK. | |
| State | is_enabled(target) |
mobile.is_enabled("Submit") |
Clickable state check. |
is_visible(target) |
mobile.is_visible("Title") |
Visibility check. | |
| Wait | wait_for_page_ready() |
mobile.wait_for_page_ready() |
Waits for UI stability. |
wait_until_visible() |
mobile.wait_until_visible("OK") |
Polling wait until visible. | |
wait_until_gone() |
mobile.wait_until_gone("Load") |
Polling wait until vanished. | |
| Validation | verify_text(text) |
mobile.verify_text("Saved") |
Assert exact text exists. |
verify_present(t) |
mobile.verify_element_present("id") |
Assert element exists. | |
| Advanced | execute_shell() |
mobile.execute_shell_command("ls") |
Raw shell access. |
execute_adb() |
mobile.execute_adb("devices") |
Raw ADB command. | |
find_by_image() |
mobile.find_by_image_click("p.png") |
Visual Match + Click. |
🏗️ 4. CLI Tooling Reference
| Command | Example | Description |
|---|---|---|
init |
apppilot init |
Scaffolds a new project. |
setup |
apppilot setup --project_folder tests |
Initializes project in specific folder. |
--overwrite |
apppilot setup --overwrite |
Overwrites apppilot.yaml with latest defaults. |
doctor |
apppilot doctor |
Dependency and tool path health check. |
devices |
apppilot devices |
Lists all connected device serials. |
interactive |
apppilot interactive |
Live REPL: Run commands one-by-one. |
run |
apppilot run |
Standard test execution. |
report |
apppilot report |
Generates/Serves HTML test report. |
📂 5. Configuration (apppilot.yaml)
# apppilot.yaml
tools:
adb_path: 'C:\path\to\adb.exe'
scrcpy_path: 'C:\path\to\scrcpy.exe'
log_path: '.apppilot/logs' # Custom log folder
mirror_screen: true
auto_scroll: true
timeout: 30
recorder_refresh_delay: 1.5 # Time (in seconds) to wait for screen transitions before refreshing the recorder view
Note for Windows Users: Always use single quotes
'for paths to avoid errors with backslashes.
🛠️ 6. Discovery & Debugging Example
When you are automating a new app and don't know the IDs, use this "Discovery Script" to find everything you need.
import pytest
from apppilot.api.mobile import Mobile
def test_discovery_session(mobile):
# 1. Launch the app and check health
mobile.launch_app("com.android.chrome")
mobile.diagnose() # Prints CPU/Memory and current Activity
# 2. Navigate to a complex page
mobile.navigate("https://www.google.com")
mobile.wait_for_page_ready()
# 3. Inspect the UI to find hidden locators
# This will print every INPUT, BUTTON, and TEXT with coordinates
mobile.inspect()
# 4. Use Relational Selectors for elements without IDs
# "Find the input to the right of the Google Search icon"
mobile.right_of("Google Search").input().fill("AppPilot Mobile")
# 5. Check performance after interaction
perf = mobile.get_performance()
print(f"Current App Memory Usage: {perf['memory_mb']} MB")
mobile.press_key(66) # Enter
mobile.screenshot("discovery_result")
© 2026 AppPilot Mobile Framework | Built for Engineers.
Metadata
Release files for apppilot 1.2.45
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| apppilot-1.2.45-py3-none-any.whl | Python 3 | none | any | Details |
| apppilot-1.2.45-cp313-cp313-win_amd64.whl | CPython 3.13 | CPython 3.13 | Windows x86-64 | Details |
Total release size: 4.1 MB
Release files / apppilot-1.2.45-py3-none-any.whl
| Download URL | apppilot-1.2.45-py3-none-any.whl |
|---|---|
| Size | 131.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e557e84a2012a08e4ad074ab3d953e301e9766af1fa08b04debdb77cc8de839d
|
|
BLAKE2b-256 checksum How to use checksums |
7ac12b079d4c0e643024b532b13194dc624b578ba6e5a628c58a8a026420a34f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / apppilot-1.2.45-cp313-cp313-win_amd64.whl
| Download URL | apppilot-1.2.45-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 4.0 MB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
5b3c1f4f870b6d729a1f8b2e0a7357872275970e1ea8b59ae8f0b19d931d5b00
|
|
BLAKE2b-256 checksum How to use checksums |
539edc240093bb1bb9da06f1f632e06ae0a25cc21b812abd54dd369e999febd4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.14
|
Security for apppilot 1.2.45
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.