云计算百科
云计算领域专业知识百科平台

EasyClick iOS 免越狱自动化脚本怎么写:从环境判断到跑通第一个脚本

iOS 免越狱自动化脚本怎么写:从环境判断到跑通第一个脚本

本文讲的是 iPhone 的免越狱、免签名自动化:不需要越狱,也不需要给应用签名。
示例环境为中控端程序 + 真机,涉及坐标、等待、重试这些工程细节,适合做移动端自动化或测试的同学参考。

一把椅子,三个小时

认识一个人,做电商客服外包,想把「每天早上把二十几个后台的订单状态过一遍」这件事交出去。

他先看了官方文档,发现函数一大堆,不知道从哪下手;又听说「免越狱、USB HID、代理模式、蓝牙」这些词,更糊涂了——四个词都听过,但不知道跟写脚本有什么关系。

那三天他的状态是这样的:第一天装环境,第二天试着看懂一个例子,第三天在纠结「到底该用哪个事件模块」。真正开始写代码,已经是第四天。

这篇就是把那四天压缩成一篇。顺序按「一个脚本从零到跑起来」的真实路径走,每个环节给出官方文档里的真实函数名和参数,不绕概念。写 iOS免越狱脚本 最耗时间的从来不是逻辑,是搞清楚每个函数到底返回什么。
在这里插入图片描述


一、先想清楚:脚本里的「免越狱」到底指什么

很多人一上来就纠结「免越狱能不能做 XX」,其实先要把这个词的含义定下来。

免越狱不等于「不装东西」 ,它指的是不改动系统。iOS 的沙箱、签名机制、系统完整性都不动,你的手机还是一台能正常升级、保修有效的手机。自动化之所以能做到这一点,是因为它只需要两件事:

  • 看到屏幕(截图或投屏)
  • 送出输入(点击、滑动、打字)
  • 这两件事都有系统本身就开放的路子,不需要打开系统。所以「免越狱脚本」的完整含义是:在不改动系统的前提下,程序化地完成「看屏幕 + 送输入」这件事。

    理解这一点之后,很多问题就自然消解了——比如「免越狱脚本能不能改系统设置」,答案是不能,因为它压根没碰系统;而绝大多数业务场景要的也不是改系统,是「按时把一批固定操作做完」。写 iOS自动化脚本 的门槛之所以比想象中低,也是这个道理:你要的能力就两样,别的都不用碰。


    二、三条链路,脚本写法差在哪

    这是新手最容易卡住的地方。同一个业务逻辑,在不同链路上要调用不同的事件模块:

    链路事件模块系统要求额外要准备
    代理模式 agentEvent iOS 13+ 签名 IPA
    USB HID usbHidEvent iOS 17+ 一根数据线
    蓝牙 BLE bleEvent iOS 17+ ESP32 开发板
    OTG HID otgEvent iOS 17+ 开发板 + 转接头

    iOS 17 是个硬门槛。官方文档的原话是:USB HID 和蓝牙 BLE 都要求 iOS 17 及以上,低于 iOS 17 只能用代理模式。手上是老机器的话,先确认版本再动手,能省掉大量无效尝试。

    顺带说清免签名这件事:代理模式要签名 IPA,而 USB HID、蓝牙、OTG 这三条硬件链路都不需要签名——不用买证书,也不用管证书什么时候过期。这是很多人选硬件链路的第一个理由。

    好消息是四个模块的方法名是一致的:

    四个模块都有的方法:
    clickPoint(x, y) 点击坐标
    press(x, y, duration) 长按
    doubleClickPoint(x, y) 双击
    swipeToPoint(x1,y1,x2,y2,duration) 滑动
    multiTouch(fingers) 多点触控
    touchDown / touchMove / touchUp 按下/移动/抬起(自己拼手势)
    systemKey(…) 系统键(Home、音量等)
    keyPress / keyPressChar 按键与字符输入

    也就是说:业务逻辑写一遍,换链路只改模块名。设计脚本时这一点值得利用——把点击操作包一层函数,链路切换只改那一处:

    // 把事件模块包一层,换链路只改这里
    const EV = usbHidEvent; // 代理模式换成 agentEvent,蓝牙换 bleEvent,OTG 换 otgEvent

    function tap(x, y) {
    return EV.clickPoint(x, y);
    }

    各自还有一点专属接口,用到时再查文档即可(比如蓝牙的 bleEvent.openSerial、setWifiInfo,OTG 的 otgEvent.scanOtgDevice、isOtgConnect)。


    三、环境准备:动手前要确认的四件事

  • 手机系统版本 —— 决定你能走哪条链路(见上表)
  • 自动化服务状态 —— 中控里能看到服务是否就绪,这是脚本能不能跑的前提
  • 授权类型 —— 执行脚本要 USB 设备授权,投屏要 USB 投屏授权,两者不是同一个。买错授权是这个环节最常见的坑
  • 屏幕尺寸 —— 后面写坐标全靠它
  • 前三项在装完环境后自然就绪,第四项要专门说一下:坐标和投屏画面、截图是同一套像素坐标,所以要么在投屏里量,要么用节点自带的坐标。USB HID 链路要显式设置屏幕尺寸(usbHidEvent.setScreenSize(w, h)),不设的话坐标换算没有依据,点哪偏哪。


    四、第一个脚本的骨架

    不管哪条链路,开头的结构是固定的。下面这份可以直接抄:

    function main() {
    logd("检查自动化环境…");
    if (!autoServiceStart(3)) {
    logw("自动化服务启动失败,无法执行脚本");
    exit();
    return;
    }

    // 节点抓取参数,脚本开头设一次就够
    setFetchNodeParam({
    "labelFilter": "2", // 只取有 label 的节点
    "visibleFilter": "2", // 只取 visible = true 的
    "maxDepth": "20", // 层级越少越快,建议 1-500
    "excludedAttributes": "visible,selected,enable,accessible"
    });

    // … 业务代码

    logd("脚本执行结束");
    }

    // 环境检查:官方示例里给出的写法,直接用
    function autoServiceStart(time) {
    for (let i = 0; i < time; i++) {
    if (isServiceOk()) {
    return true;
    }
    let started = startEnv();
    logd("第" + (i + 1) + "次启动服务结果: " + started);
    if (isServiceOk()) {
    return true;
    }
    }
    return isServiceOk();
    }

    main();

    关于 autoServiceStart :它不是系统函数,是官方示例里给出的辅助写法。思路很朴素——循环调 startEnv(),再用 isServiceOk() 检查,最多试 time 次。这比自己写一个 sleep(5000) 然后赌服务起来了要可靠得多,建议直接沿用。

    关于 setFetchNodeParam :这个参数表对性能影响比你想象的大。文档里说 excludedAttributes「可以增加抓取速度」——设备一多,少抓几个用不上的属性,累积下来差异很明显。maxDepth 建议 1–500,越小越快。

    如果走 USB HID ,开头换成 HID 自己的会话启动:

    let r = usbHidEvent.sessionStart(true); // 参数是「是否尝试增强兼容模式」,默认 true
    if (!(r == null || r === "")) {
    logw("开启 HID 会话失败: " + r);
    return;
    }
    r = usbHidEvent.setScreenSize(1170, 2532); // 坐标换算依赖这一步

    返回值约定要记住:null 或空字符串代表成功,其它字符串是错误信息。这是全文所有代码判断的基础,也是新手最容易搞反的地方。


    五、常用函数清单:五类够用

    文档里函数很多,但真正每天用的就那么几十个。按用途分五类:

    1. 环境与服务

    函数作用
    isServiceOk() 自动化服务是否就绪
    startEnv() / closeEnv() 启动 / 停止运行环境
    isDeviceOnline() 设备是否在线
    isDeviceAuthOk() / getDeviceAuth() 授权状态
    sleep(毫秒) 暂停执行
    logd / logi / logw / loge 四档日志输出

    2. 交互(点击与手势)

    四个事件模块的方法名一致,上面已列出。代理模式下还有 agentEvent.touchDown / touchMove / touchUp 用来拼自定义手势。

    3. 节点(找元素,最常用的一类)

    节点查询是链式写法,不是传配置对象:

    // 按文字找(正则匹配),最多等 5 秒
    let nd = labelMatch("发布").getOneNodeInfo(5000);
    // 按 id 找
    let nd2 = id("com.example.app:id/btn").getOneNodeInfo(3000);
    // 拿全部匹配
    let list = labelMatch(".*订单.*").getNodeInfo(5000);

    可用的筛选器:id / idMatch、label / labelMatch、name / nameMatch、type / typeMatch、value / valueMatch、xpath,以及 visible、enable 这类属性。

    节点对象上能拿到:id、xpath、label、name、type、value、bounds、index、depth、visible、enable,方法有 clickCenter、clickRandom、parent、child、allChildren、siblings、previousSiblings、nextSiblings。

    每次查询前先 releaseNode() 再 lockNode() ——官方示例固定这么写。先释放上一轮数据,再锁定当前界面,否则可能读到上一屏的节点。

    4. 输入文字

    代理模式走输入法模块:

    if (imeApi.isOk()) {
    let r = imeApi.input("要输入的内容");
    logd("输入结果: " + r); // 空字符串代表输入失败,非空是实际输入的内容
    }
    imeApi.setClipboard("#话题标签"); // 长文本建议走剪贴板
    imeApi.paste();
    imeApi.dismiss(); // 收起键盘,别漏

    imeApi.dismiss() 这一步最容易漏。输入完不收键盘,键盘会一直占着下半屏,把下面的按钮挡住,点击落到键盘上,而失败不报错、只表现为「操作没生效」。

    USB HID 链路是另一套:usbHidEvent.inputText()(走剪贴板粘贴)、usbHidEvent.typeText()(键盘打字,遇非英文自动粘贴)。

    5. 图色、截图与设备

    函数作用
    image.captureFullScreen() 全屏截图
    image.findImage(…) / findImageByColor(…) 找图 / 偏色找图
    image.cmpColor(…) 比色
    device.getDeviceInfo() 设备信息(取实时屏幕宽高用它)
    device.getDeviceId() / getDeviceName() / getModel() / getOSVersion() 设备标识与版本
    device.getBattery() / isCharging() 电量
    device.applist() 已安装应用列表

    节点查不到的时候,图色是兜底手段;需要留证或排查的时候,截图是标配。


    六、坐标怎么写才不会点歪

    坐标问题占了新手失败原因的一半,值得单独讲。

    优先用节点自己的坐标,不要手量。 节点对象带 bounds,直接算中心点:

    let nd = labelMatch("确认").getOneNodeInfo(5000);
    if (nd) {
    clickPoint(nd.bounds.centerX(), nd.bounds.centerY());
    }

    这样写的好处是换机型、换分辨率都不用改——坐标是从当前设备实时算出来的。

    确实要写硬坐标时,注意三件事:

  • 坐标基准是投屏画面/截图的像素坐标,不是逻辑分辨率
  • 分辨率变化或横竖屏切换后必须重设屏幕尺寸,USB HID 是 setScreenSize(w, h),蓝牙和 OTG 也有各自同名接口
  • 竖屏和横屏是两套坐标系,混用时需要用 adjustScreenOrientation 切换,别指望自动识别
  • 能不用坐标就别用。 一条经验:如果某个位置只能用坐标,说明那里大概率是长度不固定的列表或图标,这种地方正是最容易被版本更新搞坏的。


    七、等元素,还是等时间

    这是脚本稳不稳的分水岭。

    固定等待(sleep) 的问题在于它跟现实脱节:网络快的时候白等,网络慢的时候还没加载完就开始点。短期凑合可以,长期一定出问题。

    正确做法是把等待交给查询函数 ——getOneNodeInfo(timeout) 里的超时参数就是天然的等待:传 15000 就是「最多等 15 秒」,元素提前出现会立刻返回。

    // 不好的写法
    sleep(3000);
    clickPoint(585, 2280);

    // 好的写法
    let btn = labelMatch("下一步").getOneNodeInfo(15000);
    if (btn) {
    clickPoint(btn.bounds.centerX(), btn.bounds.centerY());
    } else {
    logw("15 秒内没出现,可能界面变了");
    }

    需要等「元素消失」时,用循环查 + sleep 小步轮询(每次 300–500ms,最多几十次),比一次性睡很久好。


    八、调试:三层工具配合用

    脚本跑不通的时候,按这个顺序查,比盯代码快得多。

    第一层:日志。 在关键步骤前打一行 logd("步骤名"),成本一行,收益是「失败时知道停在哪」。这比事后猜要省事得多。

    第二层:截图。 失败分支里加一句 image.captureFullScreen()。绝大多数失败是「停在了意料之外的页面」——弹窗、更新提示、登录过期。看到截图基本就定位了。

    第三层:中控的实时日志和执行历史。 前者看单台设备的逐步输出,后者看多设备的结果汇总。执行历史里能直接看到哪台失败、失败在哪一步,是排查多设备问题的入口。

    在这里插入图片描述

    一个实用习惯:新脚本先在单台设备上跑,第一步只做最短的动作。比如只做「打开 App 并确认首页出现了」,跑通再往下加。一上来写完整流程,失败时你无法判断是环境问题、定位问题还是逻辑问题。


    九、从一台到多台:脚本怎么下发

    单台跑通之后,下一步是铺开。中控里的做法很直接:

  • 把编译好的 iec 文件放进中控左下角的脚本目录,右键 → 刷新
  • 选中目标设备(或先在分组栏分好组),右键脚本 → 执行脚本
  • 分组这件事在设备超过十台之后就从"锦上添花"变成"必须" :几十台塞在一屏里,你根本看不出哪台失败了;分成几组,问题一眼可见。

    前面提过的那条边界再强调一次:执行脚本要 USB 设备授权,投屏要 USB 投屏授权。另外,同一台设备同一时间只跑一个任务,所以批量提速靠的是设备数量,不是单台并发。

    这也是 iOS群控 和"多写几个脚本"的分界线:脚本解决"一件事怎么做",群控解决"同一件事怎么在几十台上同时做对、并且知道哪台没做对"。

    需要和外部系统对接时(比如让电商后台自动触发),可以走开放接口,参数和返回值都是 JSON,用 Python、Node、cURL 都能调。这块展开是一篇单独的篇幅,先记住入口在中控的 8019 端口即可。


    十、进阶:脚本写稳之后的三件事

    工程化。 脚本一长,纯 JS 单文件就难维护了。文档里给了 npm 和 TypeScript 的支持方式,可以按工程结构组织代码。

    保护。 脚本要交给别人用的时候,源码就是资产。文档里有专门的 JS 混淆说明,可以在发布前处理一遍。

    参数化。 把账号、关键词、时间点这些经常改的东西抽成配置,而不是写死在流程里。这一条决定了你的脚本能用多久——改版一次就要重读源码的脚本,没人愿意维护。


    十一、按场景推荐怎么配(想跳过过程就看这节)

    如果你不想读完上面十节,这一节就是结论。下面五种情况基本覆盖了绝大多数团队,对应的都是同一套中控里的不同入口。

    你的情况推荐方案为什么
    iOS 13–16,或流程复杂、需要精确识别界面元素 推荐 EasyClick 代理模式 功能最全,有节点选择器,调试最方便
    iOS 17+,想省掉签名成本,界面比较稳定 推荐 EasyClick 加 USB HID 一根数据线,免签名免开发板,风控也更温和
    iOS 17+,风控压力大,或者设备分散摆放 推荐 EasyClick 加蓝牙 HID 风控最友好,不受线长限制
    完全不想写代码 推荐 EasyClick AI 智能体 中文对话描述任务,或拖拽出工作流
    要让自己的系统来触发设备操作 推荐 EasyClick 开放接口 8019 端口,HTTP 加 JSON,任何语言都能接

    这五种情况有一个共同点:它们共用同一个中控、同一套授权、同一批设备。所以实际落地时很少是"只选一种"——更常见的组合是先用代理模式把流程逻辑跑通,风控有压力了切到 HID,临时性的任务交给 AI 智能体,固定的批处理用脚本加定时。

    一句话总结:选平台比选单点方案重要。单点方案决定某一件具体的事怎么做,平台决定这几条链路和入口能不能共用一套设备与授权管理。上面这张表里的五种情况,在 EasyClick 里对应的是同一个平台的不同入口,不是五套要分别学的工具。

    十二、常见问题

    「免越狱」是不是不能做需要登录的操作?

    能做。登录属于应用层操作,跟越狱无关。要注意的是登录态会过期,脚本里得处理「发现要求登录 → 走一遍登录流程」这条分支。

    要不要一开始就上最复杂的方案?

    不要。三条链路各自能做到哪一步不一样,但业务逻辑是同一套。先用最容易跑通的那条把逻辑验证一遍,再按风控和规模要求换链路——换的时候只改事件模块。

    脚本里的等待该设多长?

    给足上限,不要卡得太紧。getOneNodeInfo(15000) 不会真的等 15 秒,元素出现就返回;但如果上限设 3000,网络稍慢就失败。用户不差这十几秒,但会介意脚本莫名失败。

    为什么同样的脚本在另一台设备上就不行?

    三个常见原因:分辨率不同但坐标写死了、系统版本不同导致界面差异、那台设备的自动化服务或授权状态不对。按这个顺序查。


    写脚本这件事,门槛其实不在语言。那位做客服外包的朋友最后是这么开始的:先只写「打开后台 → 等订单列表出现 → 截图」,跑通之后再逐步加动作。四个小时后他有了第一个能用的脚本;那四天里花掉的三天,全都耗在「不知道该从哪开始」上。

    先把环境和服务判断写对,再挑最短的一个动作跑通,剩下的就是加步骤——顺序对了,就不会再卡四天。iPhone自动化 这件事的入门成本,比大多数人预想的低,难的是把它做稳。

    想先看具体某条链路怎么落地,可以读iOS免越狱自动化三条链路怎么选;USB HID 的原理和 API 细节,看USB HID 的原理与 API;一篇完整的实战代码参考,可以读发短视频脚本的完整代码示例。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » EasyClick iOS 免越狱自动化脚本怎么写:从环境判断到跑通第一个脚本
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!