Install
openclaw skills install 12306-android-adb12306-specific knowledge for booking train tickets. Covers app UI structure, station search behavior, booking flow, and common pitfalls. Uses the appium-android-adb bridge for all screen interaction — NEVER use raw ADB commands on 12306.
openclaw skills install 12306-android-adb12306-specific knowledge, workflows, and pitfalls. For screen interaction, use the appium-android-adb skill (bridge_daemon.py).
Start the Appium bridge (once per session):
bash ~/.openclaw/workspace/skills/appium-android-adb/start_bridge.sh
All screen interactions use python3 ~/.openclaw/workspace/skills/appium-android-adb/bridge_daemon.py <command>.
The 12306 app uses UC WebView for the train list and booking pages. ADB input tap is IGNORED. Always use bridge_daemon.py from appium-android-adb.
| Page | Package/Activity | How to Detect |
|---|---|---|
| Home | com.MobileTicket / MainActivity | ticket_home_btn_search button exists |
| Train list | com.MobileTicket / H5Activity | title contains <> (e.g. "上海 <> 苏州") |
| Booking | same H5Activity | "预订" buttons exist |
| Confirmation | same H5Activity | "提交订单" button exists |
| Payment | same H5Activity | "立即支付" or "去支付" button |
| Element | Resource ID |
|---|---|
| Search button | ticket_home_btn_search |
| Departure station | home_page_train_dep1 |
| Arrival station | home_page_train_arr1 |
| Date container | home_page_depart_date_view_container |
Any station in a city searches ALL stations in that city. Example:
Once you have ANY valid city-to-city search result, NEVER go back to change stations. If the target train isn't immediately visible, just scroll — it's in the list.
dump → check current stations and date
If stations show any valid city pair (e.g. "上海虹桥→苏州" or "上海→苏州北"):
→ SKIP station changes. All trains from both cities will appear.
If stations are completely wrong:
→ tap departure, pick ANY station in correct city
→ tap arrival, pick ANY station in correct city
tap date container → pick target date
tap "查询车票"
dump → check trains[] for target train number
scroll down → dump → repeat until target appears
tap train by text (e.g. '{"text": "G7004"}')
→ train detail / booking page appears
dump → see seat options, look for "预订" buttons
tap '{"text": "预订", "index": 0}' → first is usually 二等座
If alert with "指纹" appears: tell user to authenticate on phone. Wait, then dump to verify.
dump → verify train, passenger, seat, price
If passenger not selected: tap "选择乘车人" → tap passenger name
tap "提交订单"
dump → tap "立即支付" or "去支付"
→ User handles Alipay/WeChat login manually
dump the screen:
├─ package != "com.MobileTicket" → app not in foreground, tap app icon or adb shell monkey
├─ "ticket_home_btn_search" in buttons → HOME PAGE
│ → ensure valid city pair (any station!) + date → tap 查询车票
├─ title contains "<>" → TRAIN LIST
│ → scroll + dump to find target train → tap it
│ → NEVER go back to change stations — scroll instead
├─ "预订" in buttons → BOOKING PAGE
│ → tap 预订 for seat type
├─ "提交订单" in buttons → CONFIRMATION
│ → verify details → select passenger → submit
├─ "立即支付" in buttons → PAYMENT
│ → tap to pay, user handles auth
└─ alerts not empty → dismiss first, re-dump
adb_helper.py — Low-level ADB helper (native element dump/find/tap/swipe). Use for pre-Appium checks or native-only pages.SKILL.md — This file. 12306-specific knowledge.README.md — Reference docs.