TOTO 外部 WebSocket 接口规范

版本:v0.4 · 更新时间:2026-02-17 · 目标:后端统一网关、外部/内部解耦、权限与路由统一治理。 接口共计 35 个 op(含事件流),全部可在 联调助手 中实时验证。

接入地址
ws://127.0.0.1:9877/control
接口规模
35 个 op (含事件流)
路由策略
scrcpy first, fallback adb
多语输入
Toto IME 优先策略
文档说明: 本文档采用「左侧分支目录 + 右侧详情」布局,可直接作为本地 API 门户使用。 点击左侧导航可快速跳转。欲进行交互式测试,请打开 联调助手

消息信封(统一格式)

请求 (Request)

{
  "id": "req-1001",
  "op": "device.list",
  "token": "session-token",
  "data": {},
  "ts": 1760000000000
}

响应 (Response)

{
  "id": "req-1001",
  "ok": true,
  "code": "OK",
  "message": "success",
  "data": {},
  "ts": 1760000000042
}

事件 (Event)

{
  "event": "notification.received",
  "data": { "serial": "192.168.1.196:5555", "packageName": "com.tencent.mm" },
  "ts": 1760000000060
}

权限模型

等级说明示例
Public无需登录system.ping
LoginRequired需要登录device.list, ime.list
ProRequired高级能力(预留)AI 自动化策略集
InternalOnly仅内部通道UI 维护类命令

目标选择器与路由优先级

target 结构

{
  "target": {
    "serials": ["192.168.1.196:5555"],
    "deviceIds": ["ca32f152c0f9521b"],
    "displayIndexes": ["2"],
    "allOnline": false
  }
}
设备接口至少提供一个选择器。通知相关接口建议始终传 serial,避免多路由不确定性。

通道策略(已执行)

能力优先回退说明
输入控制 (key/pointer)scrcpy_controladb_tcp低延迟、适合实时控制
输入法列表 (ime.list)scrcpy_serveradb_tcp优先快速链路,避免 ADB 慢查
文件传输scrcpy_fileadb_tcp大文件优先快通道
应用管理adb_tcp-以系统命令稳定性优先

分支 01:System / Device

OP功能目标要求状态
system.ping网关探活 已实现
device.list列出设备及在线状态 已实现
device.identity.get查询 serial/deviceId可选 target 已实现
device.update更新 alias/displayIndex需要 target 已实现

分支 02:Screen

OP功能目标要求状态
screen.capture单设备截图需要 target 已实现
screen.capture.batch批量截图需要 target 已实现

分支 03:Input / Clipboard

OP功能通道状态
input.key按键 keyCodescrcpy_control 已实现
input.quickkeyhome/back/recent/menu/powerscrcpy_control 已实现
input.pointer点击/拖拽/触摸scrcpy_control 已实现
input.scroll滚动scrcpy_control 已实现
input.text单设备文本输入Toto IME 已实现
input.text.batch批量文本输入Toto IME 已实现
clipboard.write写入剪贴板scrcpy_control(无 ADB 回退) 已实现

分支 04:IME

OP功能关键点状态
ime.list获取输入法列表scrcpy_server 优先 已实现
ime.select切换输入法需要 imeId 已实现
ime.ensure.toto确保 Toto 可用批量初始化 已实现
ime.install.toto安装 Toto IME需要 apkPath 已实现
推荐策略:imePolicy=toto_required,确保中英日韩等多语种稳定上屏。

分支 05:Notification

OP功能目标要求状态
notification.monitor.set开启/关闭监听建议 serial 已实现
notification.stream.subscribe订阅通知事件流serials + pkgs 已实现
notification.click按 key 点击通知serial + key 已实现
注意: Android 15/16 的后台拉起限制(BAL hardening)会影响通知点击结果。返回成功不代表一定拉到前台,需结合 click.result 事件判断。

分支 06:App

OP功能备注状态
app.list应用列表当前固定返回三方应用 已实现
app.launch启动应用packageName 已实现
app.launch.batch批量启动应用target 批量 已实现
app.stop停止应用force-stop 已实现
app.install安装 APKreplaceExisting 已实现
app.uninstall卸载应用测试机可用 已实现

分支 07:File

OP功能路由状态
file.upload上传文件scrcpy_file 已实现
file.pull拉取文件scrcpy_file 已实现

分支 08:Tag

OP功能目标要求状态
tag.list列出分组 已实现
tag.create创建分组name 已实现
tag.update修改分组tagId 已实现
tag.delete删除分组tagId 已实现
tag.device.add设备入组tagId + target 已实现
tag.device.remove设备移出分组tagId + target 已实现

分支 09:ADB

OP功能限制状态
adb.exec执行 adb shell当前未强制白名单 已实现

API 实现细则(基于当前代码)

说明: 本节按当前 ExternalApiGateway.cs + CloudPhone.ExternalApi.cs 的真实逻辑整理, 并经 联调助手 实测验证。

通用执行规则(先看)

  • 统一信封: 请求必须是 JSON 对象,包含 id/op/token/data/tsdata 不是对象会报 BAD_REQUEST(多数接口)。
  • 设备选择器: 网关解析顺序支持 data.serialdata.serialsdata.target.serialsdata.target.deviceIdsdata.target.displayIndexesdata.target.allOnline
  • displayIndex 兼容: 2/02/002 会归一后匹配,避免前端显示编号和接口编号格式不一致。
  • 批量返回模型: 大部分设备接口外层固定 ok=true/code=OK,每台设备结果在 data.results[] 里看 success/code/message/detail/data
  • 无目标行为: 目标为空时不报错,返回 message=no_targetstotal=0

11.1 System / Device(4)

API请求字段(当前实现)执行逻辑(真实)返回与错误码
system.ping data 可空对象 网关本地直接返回,不依赖设备和 provider。 data: status/service/op/serverTimeUnixMs/version
message: pong
device.list 无额外字段 调用设备快照 provider,并按 displayIndex + serial 排序。 data: devices[] + count,字段含 serial/androidId/model/status/displayIndex/alias/connectMode/isOnline/width/height
device.identity.get data.target 可选:serials/deviceIds/displayIndexes/allOnline 按 target 过滤设备;displayIndex 自动做 2/002 等价匹配。 data: identities[] + count
错误: BAD_REQUEST(data JSON 非法)
device.update data.items[],每项可带 serial/deviceId/androidId,更新字段是 displayIndexalias 设备定位优先 serial,其次 androidId/deviceId;displayIndex 会标准化为 3 位(如 2→002);alias 截断到 64 字符。 data: results[]/total/updated/failed
项级错误码: DEVICE_NOT_FOUNDANDROID_ID_UNAVAILABLEindex_conflictinvalid_indexduplicate_index_in_requestinvalid_androidIdUPDATE_FAILEDBAD_REQUESTINTERNAL_ERROR
detail: 失败时会透出 error/conflictIndex/conflictOwnerKey/requestedDisplayIndex
空 items: message=no_items

11.2 Screen / Input / IME(13)

API请求字段(当前实现)执行逻辑(真实)返回与错误码
screen.capture
screen.capture.batch
设备选择器 + 可选 saveDirformat 逐设备截图,文件名为 {displayIndex}_{yyyyMMdd_HHmmss}.png;当前实现底层走 ADB capture。 项级 data: serial/filePath/sizeBytes
项级错误码: CAPTURE_FAILEDINTERNAL_ERROR
detail: 含路由/原始结果
input.key keyCode 必填;action 可选(down/up,默认 down);metaState 可选 优先 scrcpy_control(SendKeyFromWeb),无 scrcpy 时回退 ADB input keyevent 项级 data: serial/keyCode/action/metaState
项级错误码: BAD_REQUESTINPUT_FAILEDINTERNAL_ERROR
input.quickkey quickKeyaction 必填 支持 home/back/recentapps(recent/recents/overview)/menu/power;映射 keyCode 后走 scrcpy 或 ADB。 项级 data: serial/quickKey/keyCode
项级错误码: BAD_REQUEST(不支持的 quickKey)、INPUT_FAILED
input.pointer action/x/y,可选 pointerId/screenWidth/screenHeight scrcpy 时直接发送触控;ADB 回退时坐标支持 0~1 比例或绝对值,move 用短 swipe,其他用 tap。 项级 data: 含归一化坐标和绝对坐标
项级错误码: INPUT_FAILEDINTERNAL_ERROR
input.scroll x/y/deltaX/deltaY,可选 screenWidth/screenHeight scrcpy 时发送滚动事件;ADB 回退按 deltaY 计算 swipe 距离(有最小/最大保护)。 项级 data:startY/endY 等计算结果
项级错误码: INPUT_FAILED
input.text
input.text.batch
text 必填;可选 imePolicy scrcpy 在线时按文本策略选路由:toto_ime_broadcast / clipboard_paste / scrcpy_text;无 scrcpy 时回退 toto_ime_broadcast_adb 项级 data: serial/route/textLength
项级错误码: BAD_REQUESTTEXT_CHANNEL_UNAVAILABLE
clipboard.write text 必填 要求活跃 scrcpy 通道(SendSetClipboard),不走 ADB 回退。 项级错误码: SCRCPY_NOT_READYBAD_REQUEST
项级 data: serial/textLength
ime.list 只需要设备选择器 先尝试 scrcpy_server(1.2s 超时);失败回退 ADB(ime list/settings)。 项级 data: currentImeId/inputMethods[]/count
inputMethods 字段: imeId/packageName/serviceName/appName/enabled/isCurrent
detail: route=scrcpy_serverroute=adb_tcp + fallback 原因
ime.select imeId 必填;enableIfNeeded 可选(默认 true) 执行 ime enable + ime set 并校验 default_input_method;切到 Toto 后自动尝试补齐通知监听/悬浮窗链路。 项级 data: requestedImeId/resolvedImeId/currentImeId
项级错误码: IME_NOT_FOUNDIME_SWITCH_FAILED
ime.ensure.toto 无额外字段 固定确保 com.toto.ime/.TotoImeService:enable/set + listener 权限 + overlay 权限 + monitor enable。 项级 data: resolvedImeId/currentImeId/monitorEnabled
项级错误码: TOTO_IME_NOT_FOUNDIME_SWITCH_FAILED
detail: 多行步骤日志
ime.install.toto 可传 apkPath/localPath,不传会自动找默认路径 install -r,若命中 INSTALL_FAILED_TEST_ONLY 再走 -r -t 项级错误码: APK_NOT_FOUNDINSTALL_FAILED
项级 data: serial/apkPath

11.3 Notification(3)

API请求字段(当前实现)执行逻辑(真实)返回与错误码
notification.monitor.set enabled/autoGrant,目标可用 serialtarget.serials/allOnline 逐设备执行;若 enabled=true && autoGrant=true,会尝试 listener + overlay 授权,然后广播开关监听。 data: results[]/total/successCount/failedCount
result 字段: serial/success/enabled/error/detail
无目标: message=no_targets
notification.stream.subscribe serials[]packageNames[]dropEmptyText(默认 true) 订阅条件按 clientId 存在网关内存;后续收到通知时按 serial/pkg/dropEmptyText 过滤推送。 message: subscribed
data: subscribed/clientId/serialCount/packageCount/dropEmptyText
错误: BAD_REQUEST(缺 client id)
notification.click serial 必填,key 必填(兼容 notificationKey);可选 packageName/pkg/notificationId(id)/title/text/autoGrant provider 中先校验设备在线;可选先授 overlay,再广播点击通知。 外层: 常为 ok=true/code=OK,结果在 data.result
result.code 常见: OKBAD_REQUESTDEVICE_NOT_FOUNDNOTIFICATION_CLICK_FAILEDINTERNAL_ERROR

11.4 App / File(8)

API请求字段(当前实现)执行逻辑(真实)返回与错误码
app.list 仅设备选择器 + 可选 includeSystem 按设备用 ADB 获取三方应用列表。 项级 data: apps[]/countpackageName/appName
detail: route=adb_tcp
app.launch
app.launch.batch
packageName 必填 ADB 执行 am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -p {pkg} 项级错误码: APP_LAUNCH_FAILED
项级 data: serial/packageName
app.stop packageName 必填 ADB 执行 am force-stop 项级错误码: APP_STOP_FAILED
app.install apkPathlocalPath 必填;replaceExisting 默认 true 本地文件存在校验后安装,支持 test-only 失败自动重试 -t 项级错误码: APK_NOT_FOUNDINSTALL_FAILED
项级 data: serial/apkPath/replaceExisting
app.uninstall packageName 必填 ADB 执行 pm uninstall 项级错误码: UNINSTALL_FAILED
file.upload localPath + remotePath 必填 先走 scrcpy 文件通道;失败回退 ADB push。remotePath 以斜杠结尾时自动补本地文件名。 项级 data: serial/localPath/remotePath/sizeBytes/route
项级错误码: LOCAL_FILE_NOT_FOUNDUPLOAD_FAILED
file.pull remotePath 必填;localDir 可选 先走 scrcpy 文件通道;失败回退 ADB pull。未给 localDir 时默认 Tmp/external-pulls 项级 data: serial/remotePath/localPath/sizeBytes/route
项级错误码: PULL_FAILED
adb.exec command 必填;可选 safeMode 按设备执行 ADB shell 命令并回传 output。safeMode 字段目前未参与后端校验。 项级 data: serial/command/output
项级错误码: ADB_EXEC_FAILED

11.5 Tag(6)

API请求字段(当前实现)执行逻辑(真实)返回与错误码
tag.list读取网关内存中的标签仓库(按 name 排序)。 data: tags[]/count
注意: 当前为进程内存态,重启后需重新同步
tag.create name 必填;color/description 可选 生成 GUID 作为 tagId,记录创建/更新时间。 message: created
data: tag
tag.update tagIdid 必填;可选更新 name/color/description 局部字段更新,未传字段保持不变。 message: updated
错误: TAG_NOT_FOUNDBAD_REQUEST
tag.delete tagIdid 必填 删除标签,若不存在不会抛错。 message: deletednot_found
data: tagId/deleted
tag.device.add tagId 必填;设备来源可用 target 选择器,也可直接 deviceIds[] 将目标设备集合合并去重后加入标签。设备集合为空时返回 no_targets data: tag/changed/total/action
错误: TAG_NOT_FOUND
tag.device.remove 同上 将目标设备集合从标签中移除。 data: tag/changed/total/action

错误码建议

Code说明
OK成功
BAD_REQUEST参数错误/缺失
UNAUTHORIZED未登录或 token 无效
FORBIDDEN权限不足
DEVICE_NOT_FOUND目标设备不存在或离线
IME_UNAVAILABLE输入法不可用
NOTIFICATION_CLICK_FAILED通知点击失败
NOTIFICATION_BAL_BLOCKED后台拉起受系统限制
TASK_FAILED批量任务失败
RATE_LIMITED触发限流

事件流(Notification 重点)

notification.received

{
  "event": "notification.received",
  "data": {
    "serial": "192.168.1.196:5555",
    "deviceId": "ca32f152c0f9521b",
    "packageName": "com.tencent.mm",
    "title": "微信",
    "text": "2个联系人发来4条消息",
    "key": "0|com.tencent.mm|-91455226|null|10323",
    "id": "-91455226",
    "postedAtUnixMs": 1771143920411,
    "receivedAtUnixMs": 1771143920478
  },
  "ts": 1771143920478
}

notification.click.result

{
  "event": "notification.click.result",
  "data": {
    "serial": "192.168.1.196:5555",
    "key": "0|com.tencent.mm|-91455226|null|10323",
    "success": true,
    "verified": false,
    "reason": "notification_still_active",
    "error": ""
  },
  "ts": 1771143922780
}

安全与性能基线

  • 网络边界: 外部 WS 默认仅监听 127.0.0.1,公网暴露需加代理鉴权。
  • 鉴权审计: 强制 token 校验与会话过期,保留审计日志(账号/设备/op/耗时/结果)。
  • ADB 防护: 建议上白名单与危险字符拦截;当前实现尚未强制。
  • 流控: 消息体大小限制 + 连接级限流,避免拖垮 HXT 主线程。
  • 性能优先: 涉及实时控制场景,优先 scrcpy 通道,避免 ADB 轮询导致延迟尖峰。
本规范为本地工程文档,最终行为以 ExternalApiGateway 和后端映射代码为准。 如需交互式验证,请打开 联调助手
TOTO External WS API Spec · TOTO · Local HTML Doc · 2026-02-17