用 Python 调 iOS 免越狱脚本:开放接口对接步骤与参数
本文讲的是 iPhone 的免越狱、免签名自动化:不需要越狱,也不需要给应用签名。
示例环境为中控端程序 + 真机,涉及坐标、等待、重试这些工程细节,适合做移动端自动化或测试的同学参考。
那次半夜的手动点击
一个做跨境电商的团队,客服系统里有个「订单异常」告警。出现问题件的时候,他们要到手机 App 上把那个订单重新提交一次。
问题在于告警是系统发出来的,手机操作却得人来做。半夜来一条,就得有人爬起来点一下。
他们想的是:能不能让客服系统自己去点。
这就是开放接口存在的意义——中控自己不知道什么时候该干活,但外部系统知道。把设备操作变成 HTTP 调用之后,任何会发请求的程序都能驱动手机;iPhone自动化 这件事,也就从"守着中控点"变成了"发一个请求"。
一、先想清楚:什么时候才需要这么接
开放接口不是默认选择,先判断一下你的场景。
适合走接口的三种情况:
- 触发方在中控之外—— 订单系统、告警系统、你的后台,它们知道什么时候该做什么,中控不知道
- 调度节奏由你自己控制—— 你想用自己的调度器、自己的重试策略,而不是中控的定时任务
- 结果要落进自己的系统—— 执行完的状态要写回你的数据库,而不是停在中控的执行历史里
不需要走接口的情况:
定时跑一段固定脚本,中控自己的定时任务就够了。为了"显得自动化"而多加一层接口,维护成本反而更高。
判断标准一句话:如果中控自己就能决定"什么时候做什么",就不用接口;如果这个决定来自别的系统,就需要。
二、接口长什么样
三件事定下来,剩下都是填空。这套 API接口 没有 SDK,也不需要 SDK——就是普通的 HTTP 调用,用 iOS自动化脚本 的团队拿现成的请求库就能接。
地址: 中控所在电脑的地址 +8019端口。本机调用是http://127.0.0.1:8019;从别的机器调就换成那台电脑的内网 IP。
方法: HTTP POST,Content-Type: application/json,参数放在请求体里。
返回约定: 返回 JSON,看code字段——0 代表成功,其它值代表失败,失败原因在msg里。
这个约定值得在最开始就封装掉。官方示例里的写法是这样:
importrequests BASE="http://127.0.0.1:8019"defopenapi_post(path,body=None):r=requests.post(f"{BASE}{path}",json=bodyor{},timeout=30)r.raise_for_status()data=r.json()ifdata.get("code")!=0:raiseRuntimeError(data.get("msg")ordata)returndata后面所有调用都走这个函数。Python 只依赖requests;Node.js 18+ 自带fetch,不用装东西。
三、第一步:拿到 deviceId
所有设备相关的接口都要deviceId,所以第一步永远是查设备列表:
devices=openapi_post("/openapi/deviceList",{"deviceId":"","groupId":""})print(devices)注意两个参数的含义:deviceId传空字符串表示"不按设备过滤",groupId传空表示"不按分组过滤"。想只取某一组的设备,就把groupId填上。
一个容易混的点:deviceId和别名不是一回事。 别称是你自己在中控里起的、给人看的名字;接口调用必须用deviceId。所以从列表接口的返回值里取,不要拿别名去试。
四、第二步:USB HID 的三步顺序
这是整篇文章最实用的一段。USB HID 的接口不能上来就点击,顺序是有讲究的:
DEVICE_ID="90e2f3834c0977205e441aa664916a9bdde81e8d"# 从设备列表里取# 1) 开会话openapi_post("/openapi/usbhidSessionStart",{"deviceId":DEVICE_ID,"gate":True})# 2) 设屏幕分辨率(坐标换算依赖它)openapi_post("/openapi/usbhidSetScreenSize",{"deviceId":DEVICE_ID,"w":1170,"h":2532})# 3) 之后才能点击openapi_post("/openapi/usbhidClickPoint",{"deviceId":DEVICE_ID,"x":200,"y":400})三段代码各自为什么要存在:
开会话 ——gate参数是"是否尝试增强兼容模式",低版本系统会自动忽略,所以一般传true。会话已经存在时会复用,不需要每次重新开。
设屏幕尺寸 —— 这一步最容易被跳过,然后所有点击都点偏。因为 HID 送的是绝对像素坐标,不告诉它屏幕多大,它不知道怎么换算。w和h要和你投屏、截图看到的分辨率一致。
点击 ——x、y就是像素坐标。多台设备分辨率不同的话,这个值要按设备分别算,不能写死。
顺序只在会话建立时需要。会话开着、尺寸设对之后,后面连续几百次点击都只是重复第三步,不用每次重设。
Node.js 的写法结构完全一样,只是换成了fetch:
constBASE="http://127.0.0.1:8019";asyncfunctionopenapiPost(path,body={}){constres=awaitfetch(`${BASE}${path}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body),});constdata=awaitres.json();if(data.code!==0){thrownewError(data.msg||JSON.stringify(data));}returndata;}五、十一个模块分别管什么
接口按用途分了十一组,对着这张表找比翻文档快:
| 模块 | 管什么 |
|---|---|
| 中控接口 | 设备列表、脚本启停等 |
| 自动化 · 动作 | 点击、滑动、输入、App 的打开关闭 |
| 自动化 · 截图 | 截图、图片流 |
| 自动化 · 启停自动化 | 启动 / 释放自动化、隧道、电量 |
| 自动化 · 相册 | 上传图片视频、清空相册 |
| 自动化 · 文件操作 | 设备文件推送与拉取 |
| 自动化 · IME 输入法 | 自定义输入法、剪贴板转发 |
| 自动化 · 蓝牙 BLE | 蓝牙板的 HID 动作 |
| 自动化 · USB HID | 免硬件,数据线直接控制手机 |
| 辅助助手 | 助手剪贴板、相册、端口转发 |
| 快捷指令助手 | 需配合快捷指令助手程序使用 |
「动作」是最常用的一组,包含点击、双击、长按、滑动、多点触摸、输入文本、模拟键盘、打开/关闭/安装/卸载 App、主页、重启设备、锁屏解锁、设置屏幕方向、校正坐标系、抓取节点等等,基本覆盖了脚本里会遇到的每一步。
「USB HID」这组值得单独留意:它是唯一不需要蓝牙板或 OTG 板的硬件链路,一根数据线就能模拟点击和输入,对已经在用数据线的场景最省事。
六、中控接口:查设备、启停脚本
前面几步都在讲怎么操作单台设备,中控接口解决的是"管"的问题。
它有设备列表、脚本启停这类接口。典型用法是两段式:
- 先调设备列表拿到这一批设备的
deviceId - 再对每台启动脚本,跑你编译好的逻辑
这个组合很适合"用外部策略决定跑哪些设备"的场景——比如按订单归属决定在哪些机器上跑、或者按分组轮换。
设备多的时候,分组要在中控里先做好。接口是按deviceId单台调的,你的代码里需要循环;分组能让这个循环有明确的来源,而不是每次把全部设备拉一遍。管理规模的 iOS群控 项目,这一步基本是标配。
七、和 AI 系统对接
如果你的目标是让 AI 助手直接调度手机,还有一条更省事的路:把接口注册成 MCP 工具。
区别在于:直接调开放接口,你要自己写"调哪个接口、传什么参数"的逻辑;注册成 MCP 之后,AI 助手自己会选工具、拼参数。适合"让大模型决定下一步做什么"的场景。
两条路可以并存:固定的、可预期的操作用接口直调,需要临场判断的交给 MCP。
八、落地时的几个实际问题
错误处理怎么做。 接口调用失败的原因分两类:网络/服务问题(中控没开、端口不通)和业务问题(设备离线、授权过期、坐标越界)。前者适合重试,后者重试没有意义——按msg区分,别一律重试。
超时设多少。 官方示例给的是 30 秒。实际操作类接口通常几百毫秒返回,超时设长了只是让故障暴露得慢;但截图、上传这类涉及大文件的接口要留足。建议按接口分组设,而不是全局一个值。
坐标怎么维护。 这是接口方案最容易出问题的地方。设备型号混用的时候,别写死坐标——要么按设备分辨率换算,要么优先用抓节点接口拿到元素坐标再点。后者稳得多。
日志留什么。 建议记录:设备 ID、调用的接口、请求参数、返回code与msg、时间戳。这五样在手,出问题时能直接对上,不用靠回忆。
和脚本的分工。 一个常见误区是用接口把整段流程重写一遍。更省事的做法是:流程留在设备的脚本里,接口只负责"触发"和"取结果"。接口调用次数少,网络往返少,出问题的地方也少。
九、按需求推荐怎么接(先看结论)
前面讲了接口怎么调,这一节说清"什么时候该用哪种方式"。四种需求覆盖了绝大多数场景,而且它们可以在同一套设备上并存。
| 你的需求 | 推荐方式 | 为什么 |
|---|---|---|
| 定时跑一段固定流程 | 推荐EasyClick 中控的定时任务 | 不需要绕一层接口,中控自己就能决定什么时候做 |
| 由外部系统决定何时触发 | 推荐EasyClick 开放接口直调 | 8019 端口,HTTP 加 JSON,和你现有系统直接打通 |
| 要让 AI 决定下一步做什么 | 推荐EasyClick 注册成 MCP 工具 | AI 自己选工具、拼参数,不用你写调度逻辑 |
| 既要精确控制界面元素,又要在设备上跑完整流程 | 推荐EasyClick 代理模式配脚本,接口只做触发 | 流程留在设备上,网络往返少,出问题的地方也少 |
这四种方式用的是同一个中控、同一套设备授权。所以真实项目里通常是组合着用:固定流程走定时,外部触发走接口,需要判断的交 MCP,而设备上的具体动作始终由脚本承担。
一个常见误区是用接口把整段流程重写一遍。推荐的划法是:脚本负责设备上做什么,接口负责从外面告诉它开始、以及把结果取回来。这样接口调用次数少,链路短,排查也简单。
十、常见问题
接口只能在局域网里用吗?
默认是。8019 是中控所在电脑的端口,能访问到那台电脑就能调。跨网络要么走内网穿透,要么用中控的云控方案。
能同时给多台设备发指令吗?
接口本身按deviceId单台调,并发要靠你的代码——比如用线程池同时发。注意同一台设备同一时间只跑一个任务,所以并发是"多台并行",不是"单台并发"。
调接口需要什么授权?
执行脚本要USB 设备授权,投屏要USB 投屏授权,两者不是一回事。接口里也有查询授权状态的接口,可以在启动任务前先确认一下,省得跑到一半才发现没授权。
返回 code 不为 0 但 msg 看不懂怎么办?
先看是不是设备层面的事(离线、未授权、会话没开),这三类占了大多数。剩下的按接口名去文档对应模块查——每个接口的参数和返回都有说明。
那位做跨境的团队最后是这么落地的:告警系统检测到问题件,直接调设备列表找到对应的机器,跑一次"重新提交订单"的脚本,把结果写回自己的工单表。半夜的这一次点击,从"叫醒一个人"变成了"发一个请求"。