ADB handles shell ops; Appium handles UI automation (taps, swipes, app launch) on cloud phones. Production farms connect vendor ADB first, then attach Appium with udid matching the remote serial. This recipe bridges ADB guide and vendor APIs (GeeLark/DuoPlus).
Stack
Cloud vendor API → start pad → adb connect host:port Appium 2 server (local worker) → UiAutomator2 driver → Python client Job done → driver.quit() → vendor API stop pad
Install (worker VM)
npm install -g appium@next appium driver install uiautomator2 pip install Appium-Python-Client
Capabilities template
caps = {
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appium:udid": "203.0.113.10:5555", # from adb devices
"appium:noReset": True,
"appium:newCommandTimeout": 300,
"appium:skipServerInstallation": False,
# Optional: appPackage / appActivity for TikTok, IG, Shopee
"appium:appPackage": "com.zhiliaoapp.musically",
"appium:appActivity": ".splash.SplashActivity",
}
Python session wrapper
import subprocess
import random
import time
from appium import webdriver
from appium.options.common import AppiumOptions
APPIUM = "http://127.0.0.1:4723"
def adb_connect(endpoint: str) -> None:
subprocess.run(["adb", "connect", endpoint], check=True, capture_output=True)
out = subprocess.check_output(["adb", "devices"], text=True)
assert endpoint in out and "device" in out, f"ADB offline: {out}"
def human_pause(lo=0.8, hi=2.4) -> None:
time.sleep(random.uniform(lo, hi))
def with_appium(endpoint: str, caps: dict, fn):
adb_connect(endpoint)
opts = AppiumOptions()
opts.load_capabilities({**caps, "appium:udid": endpoint})
driver = webdriver.Remote(APPIUM, options=opts)
try:
fn(driver)
finally:
driver.quit()
def warm_scroll(driver):
size = driver.get_window_size()
x = size["width"] // 2
for _ in range(3):
driver.swipe(x, int(size["height"] * 0.75), x, int(size["height"] * 0.25), 600)
human_pause()
Pair with vendor API worker
# Pseudocode — start pad via GeeLark/DuoPlus API, then Appium
async def job(pad_id: str):
adb_ep = await vendor_start(pad_id) # returns "host:port"
with_appium(adb_ep, caps, warm_scroll)
await vendor_stop(pad_id)
Anti-ban rules for Appium on cloud phones
| Do | Avoid |
|---|---|
| Random tap offsets ±8px | Pixel-perfect same coordinates |
| Variable swipe duration 400–900ms | Fixed 300ms loops |
| One session per account per day for warm tier | 24/7 scroll bots on prod devices |
| Stop pad when session ends | Leave Appium + pad running overnight |
Hybrid with Multilogin
Appium runs the native app layer. Web seller dashboards, TikTok Shop browser, Meta ads stay on Multilogin — never share login sessions between Appium app and browser profile. See hybrid architecture and TikTok Shop web guide.
Related
Disclosure: MLX-MMO affiliated with Multilogin. Appium and package names change with app updates — verify before production.