HTTP API
用纯 HTTP 请求操控手机,可以来自 curl、PowerShell、Python requests、fetch 或任何无代码工具:端点、请求体、响应、状态码和令牌。
本页为译文。如与英文版不一致,以英文版为准。 English
你的代码连接的端口 localhost:8780 也支持 HTTP。因此,任何能发送 Web 请求的语言或工具都能使用 Droidline:curl、PowerShell、无代码自动化工具,或者没有 SDK 的语言。一个请求执行一条命令,并返回一个 JSON 响应。
端点
| 请求 | 作用 |
|---|---|
GET /devices | 列出已配对的手机 |
POST /devices/{device}/{command} | 执行一条手机命令。JSON 请求体包含它的参数。 |
GET /devices/{device}/screenshot.png(或 .jpg) | 截图图片本身。也支持 ?scale=0.5&quality=70。 |
POST /server/{command} | 执行服务器命令:pair、pair_qr、rename、revoke |
GET /ws | 一个 WebSocket,传输与原始套接字相同的数据行 |
{device} 是手机的名称或 ID,也可以写 _,表示“唯一在线的手机”。{command} 是命令参考中的任意命令名,请求体使用那里列出的参数名。
第一个请求
curl -s -X POST localhost:8780/devices/_/touch \
-H 'content-type: application/json' \
-d '{"by":"text","value":"OK"}'Invoke-RestMethod -Method Post -Uri http://localhost:8780/devices/_/touch `
-ContentType "application/json" -Body '{"by":"text","value":"OK"}'import requests
r = requests.post("http://localhost:8780/devices/_/touch",
json={"by": "text", "value": "OK"})
print(r.status_code, r.json())const r = await fetch("http://localhost:8780/devices/_/touch", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ by: "text", value: "OK" }),
});
console.log(r.status, await r.json());每个 POST 都需要两样东西:
- 请求头
Content-Type: application/json。没有它,服务器会返回415,即使是不带参数的命令也一样。 - 一个 JSON 对象作为请求体。对于没有参数的命令,发送
{},或者干脆不发请求体。
响应
命令成功时返回 200,响应中带有 "ok": true,结果的各个字段直接展开在这个对象中。只返回一个值的命令把它放在 value 下:
{"ok":true,"via":"node","ms":208}
{"ok":true,"value":"12,500"}
{"ok":true,"package":"dev.droidline.demo","activity":".MainActivity"}
命令失败时,返回其错误码对应的 HTTP 状态,响应仍是同样结构的 JSON,只是带有 "ok": false:
{"ok":false,"error":"NOT_FOUND","msg":"Could not find text 'Nope' within 1s. Current screen: dev.droidline.demo / .MainActivity","retryable":true,"screen":"dev.droidline.demo/.MainActivity","target":"text 'Nope'","timeout":1}
| 状态 | 典型错误码 |
|---|---|
200 | 成功 |
400 | BAD_ARGS、DEVICE_AMBIGUOUS |
401 | UNAUTHORIZED |
404 | UNKNOWN_CMD、DEVICE_NOT_FOUND |
409 | NO_ACCESSIBILITY、NO_IME、NO_PERMISSION |
422 | NOT_FOUND、AMBIGUOUS、MACRO_FAILED,以及其他手机无法完成的操作 |
503 | DEVICE_OFFLINE、AGENT_RESTARTED |
504 | TIMEOUT |
请从响应体中读取 error 和 retryable,不要只依赖状态码。
常用请求
# 哪些手机已配对,它们是否在线?
curl -s localhost:8780/devices
# 在指定名称的手机上打开应用
curl -s -X POST localhost:8780/devices/shelf-01/launch \
-H 'content-type: application/json' -d '{"package":"com.android.settings"}'
# 屏幕上有没有某个元素?
curl -s -X POST localhost:8780/devices/_/exists \
-H 'content-type: application/json' -d '{"by":"text","value":"Close ad"}'
# 等待比默认更长的时间
curl -s -X POST localhost:8780/devices/_/touch \
-H 'content-type: application/json' -d '{"by":"text","value":"Done","timeout":30}'
# 保存界面树和截图
curl -s -X POST localhost:8780/devices/_/dump -H 'content-type: application/json' > screen.json
curl -s "localhost:8780/devices/_/screenshot.jpg?scale=0.5" -o shot.jpg
# 更换移动网络 IP,并等待手机重新上线
curl -s -X POST localhost:8780/devices/_/batch -H 'content-type: application/json' \
-d '{"steps":[["airplane",true],["sleep",3000],["airplane",false]],"wait":true}'# 哪些手机已配对,它们是否在线?
(Invoke-RestMethod http://localhost:8780/devices).value | Format-Table name, online, route
# 在指定名称的手机上打开应用
Invoke-RestMethod -Method Post -Uri http://localhost:8780/devices/shelf-01/launch `
-ContentType "application/json" -Body '{"package":"com.android.settings"}'
# 屏幕上有没有某个元素?用哈希表构建请求体。
$body = @{ by = "text"; value = "Close ad" } | ConvertTo-Json
(Invoke-RestMethod -Method Post -Uri http://localhost:8780/devices/_/exists `
-ContentType "application/json" -Body $body).value
# 保存截图
Invoke-WebRequest "http://localhost:8780/devices/_/screenshot.jpg?scale=0.5" -OutFile shot.jpg
# 捕获错误并读取错误码
try {
Invoke-RestMethod -Method Post -Uri http://localhost:8780/devices/_/touch `
-ContentType "application/json" -Body '{"by":"text","value":"Nope","timeout":1}'
} catch {
$err = $_.ErrorDetails.Message | ConvertFrom-Json
"$($err.error): $($err.msg)"
}会切断网络的命令
data(false)、wifi(false)、airplane(true) 以及包含它们的 batch 会断开手机自身的连接。通过 HTTP 调用时,请始终发送 "wait": true:这样请求会一直保持,直到手机重新上线,再返回最终结果。不这样做的话,你只会得到 {"ok":true,"accepted":true},最终结果则会发往一个已经关闭的连接。
令牌与其他机器
默认情况下,服务器只接受来自同一台电脑的连接,这些连接不需要令牌。如果你把端口开放给网络(在 config.toml 中设置 client.listen = "0.0.0.0:8780"),每个请求都需要在 Authorization 请求头中带上客户端令牌:
droidline token create "office laptop" # 只输出一次 dlc_...
curl -s -X POST http://192.168.0.12:8780/devices/_/current \
-H 'content-type: application/json' \
-H 'Authorization: Bearer dlc_...'
这样做之前,请先阅读安全。
来自网页的调用
服务器会拒绝来自网页的请求,除非网页的来源列在 client.allowed_origins 中,所以你碰巧访问的网站无法操控你的手机。要从你自己的本地 Web 应用调用这个 API,添加它的来源,例如 allowed_origins = ["http://localhost:5173"],然后重启服务器。