Appium Android Bridge
Generic Android bridge for any app. Reads screens as structured JSON, executes taps/scrolling/typing. Supports two backends:
| Backend | Best for | Limitations |
|---|---|---|
| Appium (bridge_daemon.py) | Native apps, structured dumps, find/wait |
UC WebView virtual list taps fail on collapsed elements |
| uiautomator2 (Python lib) | WebView content, scrolling, booking buttons | Conflicts with Appium (same session can't share AccessibilityService) |
Quick Start
Option A: bridge_daemon.py (Appium-based)
# Once per session (~28s):
bash ~/.openclaw/workspace/skills/appium-android-adb/start_bridge.sh
# Then all interactions (~1-2s each):
python3 bridge_daemon.py dump
python3 bridge_daemon.py tap '{"text": "查询车票"}'
python3 bridge_daemon.py scroll '{"direction": "down"}'
Option B: uiautomator2 (direct Python)
pip3 install uiautomator2 # already installed
python3 -c "
import uiautomator2 as u2
d = u2.connect()
d.app_start('com.MobileTicket')
"
Use for WebView scroll + booking button clicks. Cannot run simultaneously with Appium.
Commands (bridge_daemon.py)
All from ~/.openclaw/workspace/skills/appium-android-adb/. All return JSON.
dump — read the screen
python3 bridge_daemon.py dump
Returns:
{
"ok": true,
"package": "com.MobileTicket",
"activity": "com.alipay.mobile.nebulacore.ui.H5Activity",
"title": "上海 <> 苏州",
"alerts": [{"text": "温馨提示"}],
"buttons": [
{"text": "查询车票", "id": "", "bounds": "[99,970][981,1102]", "x": 540, "y": 1036},
{"text": "预订", "id": "", "bounds": "[870,1988][1008,2075]", "x": 939, "y": 2031}
],
"trains": [
{"text": "G 7 0 0 4次列车...", "bounds": "[66,1793][291,1919]", "clickable": true, "x": 178, "y": 1856}
],
"webview_contexts": ["NATIVE_APP"]
}
tap — click element by text
python3 bridge_daemon.py tap '{"text": "查询车票"}'
python3 bridge_daemon.py tap '{"text": "预订", "index": 0}'
python3 bridge_daemon.py tap '{"id": "btn_submit"}'
tap_bounds — click using bounds from dump
python3 bridge_daemon.py tap_bounds '{"bounds": "[870,1988][1008,2075]"}'
⚠️ Only works reliably if the element has proper bounds (h > 20px). Collapsed virtual list items (h=6px) will NOT respond.
tap_coords — click at exact coordinates
python3 bridge_daemon.py tap_coords '{"x": 540, "y": 1200}'
find — inspect element matches
python3 bridge_daemon.py find '{"text": "7004"}'
scroll — swipe the screen
python3 bridge_daemon.py scroll '{"direction": "down"}'
python3 bridge_daemon.py scroll '{"direction": "down", "distance": "micro"}'
⚠️ May not work on UC WebView (used by 12306, Alipay apps). The WebView filters touch events. For UC WebView scrolling, use uiautomator2's d.swipe_ext() instead.
screenshot — take phone screenshot
python3 bridge_daemon.py screenshot
# Returns {"ok": true, "path": "/tmp/screen.png"}
type — input text
python3 bridge_daemon.py type '{"text": "上海"}'
wait — poll until element appears
python3 bridge_daemon.py wait '{"text": "提交订单", "timeout": 30}'
When to Use Which
| Situation | Recommended Tool |
|---|---|
| Native Android views (date tabs, search buttons, bottom nav) | Either — both work |
| App dump / text search / element inspection | bridge_daemon.py dump + find |
| UC WebView content (train list, booking pages) | uiautomator2 |
| Clicking "预订" / "提交订单" / action buttons | uiautomator2 d.text('预订').click() |
| Scrolling UC WebView lists | uiautomator2 d.swipe_ext('up', scale=0.3) |
| OCR + coordinate tap | ADB input tap (works on visible content) |
| WebView text content (crashes UIAutomator2) | bridge_daemon.py dump (via Appium) |
⚠️ UC WebView Virtual List — Critical Knowledge
Apps using UC WebView (12306, many Chinese apps) use virtual lists that collapse most items' accessibility bounds:
- Visible items: Have real bounds (h=60-130px), clickable via accessibility service
- Off-screen items: COLLAPSED to y=407 (top) or y=2255 (bottom), h=6px
- Action buttons: "预订" buttons ALWAYS have proper bounds (h=87px) even in virtual lists
What Works on UC WebView
- Clicking action buttons like "预订", "提交订单", "查询车票" — they have persistent proper bounds
- Scrolling via
d.swipe_ext()in uiautomator2 - OCR + coordinate-based ADB tap (with good image preprocessing)
- Element
click()via uiautomator2 when the element has h > 20px
What Does NOT Work on UC WebView
- Clicking collapsed text elements (train names, times, seat info) — h=6px bounds
- ADB
input tapon WebView content — silently filtered by UC WebView mobile: scrollGesturevia Appium — returns False- W3C Actions swipe — touch events filtered
- JS injection (
execute_script) — no WEBVIEW contexts exposed
Troubleshooting
Daemon died: Run start_bridge.sh again.
uiautomator2 conflict: "AccessibilityService already registered" means Appium is running. Kill Appium first.
Appium session error / ANDROID_HOME: Ensure export ANDROID_HOME=/usr/lib/android-sdk before starting Appium.
G7004 text not found: Search with spaces: G 7 0 0 4, not G7004.
"预订" not found: The list may not have loaded yet. Wait and re-dump.
OCR not reading Chinese: Use lang='chi_sim+eng' with --psm 6 config.