Autox.js 的运行机制 无障碍服务是怎么让它"看见"手机屏幕的
一个 App,四个核心模块
Autox.js 看起来就是个装在手机上的应用,但它背后的运行机制比普通 App 复杂得多。理解它的四个核心模块,能帮你写出更稳定的脚本、排查更多类型的问题。
架构总览
┌─────────────────────────────────────────────────┐
│ Autox.js App │
│ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ 无障碍服务 │ │ 悬浮窗控制 │ │ 脚本引擎 (Rhino) │ │
│ │Accessibility│ │ Floaty │ │ + Node.js │ │
│ └──────┬───┘ └────┬─────┘ └────────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────┐ │
│ │ 布局分析 / 控件树 / 图像识别 │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
模块一:无障碍服务(Accessibility Service)
这是整个系统的眼睛和双手。Android 系统出于残障人士辅助功能的需求,开放了 AccessibilityService API——任何 App 只要被用户授权,就可以:
- 读取当前屏幕的 UI 控件树(每个按钮、文字、输入框的层级结构)
- 模拟点击、滑动、长按、按键
- 监听页面切换事件
Autox.js 的选择器 API(findOne()、click() 等)全部建立在这个服务之上。没有无障碍授权,Autox.js 就只是一个空壳 App。
注意:无障碍服务的权限是持续性的——开一次关不掉,除非用户手动去系统设置里关闭。这既是它能稳定运行的原因,也是系统和安全软件频繁干扰它的原因。
模块二:悬浮窗控制条(Floaty)
悬浮窗是 Autox.js 与用户交互的主要入口:
- 录制按钮:开始/停止录制操作,自动生成 JS 代码
- 运行/停止:启动或终止当前脚本
- 布局分析器:打开控件树可视化工具
- 控制台:显示
console.log()的输出
它之所以能显示在任何 App 之上,是因为用到了 Android 的 TYPE_APPLICATION_OVERLAY(悬浮窗)权限。没有这个权限,Autox.js 就无法在后台运行时展示控制条。
模块三:脚本引擎(Rhino + Node.js)
Autox.js v7 的脚本引擎有两层:
Rhino v1.8.0:Mozilla 开发的 Java 实现的 JavaScript 引擎,是 Android 上最成熟的 JS 运行时之一。v7 版本大幅升级了 Rhino 引擎,修复了内存泄漏、完善了 ES6+ 语法支持。
Node.js 运行时(v7 新增):在 Rhino 之外又加入了一个 Node.js 兼容层,支持 require() 引入模块、npm 生态。这让 Autox.js 不再只是"手机上跑 JS",而是真正具备了 Node 级别的工程化能力。
两个运行时通过桥接层互通——Node 侧可以调用 Android 的 Java 类,Rhino 侧也能加载 Node 模块。
模块四:布局分析器(Layout Inspector)
布局分析器是 Autox.js 内置的调试工具,类似 Android Studio 的 Layout Inspector。当你打开它时:
- 屏幕变成半透明蒙层
- 点击任意控件 → 弹出详情面板,显示它的
id、className、text、bounds、parent、childCount - 可以直接复制生成选择器代码,比如
id("com.example:id/btn_ok").click()
这个工具是写选择器脚本的第一生产力——不用瞎猜控件的属性,现场点一下就知道。
协作流程:一次 click 发生了什么
当脚本执行 className("Button").text("确定").click() 时:
- Rhino 引擎解析 JS 代码,触发
select()调用 - 无障碍服务读取当前界面的控件树(一次 AccessibilityEvent 或 snapshot)
- 选择器引擎遍历控件树,逐个匹配
className == "Button"且text == "确定"的节点 - 找到目标后,构造一个 AccessibilityNodeInfo 的 click 动作,通过无障碍服务发送给系统
- Android 系统把这个 click 事件派发给目标 App
整个过程不涉及屏幕坐标——它和你在屏幕上点的物理位置无关,只要控件树还在就能操作。这也是为什么控件选择器脚本比坐标脚本稳。
为什么需要 Root
大部分功能不需要 Root,但有几类操作必须 Root才能实现:
- 精准坐标点击:无障碍服务提供的 click 是"语义点击"(对控件发事件),而不是"像素级点击"(对屏幕某个坐标发触摸事件)。要做像素级操作(比如游戏画面上点一个像素点),必须通过 Root shell 执行
input tap x y命令 - 录屏生成可回放文件:无障碍服务无法录制原始触摸事件,Root 模式下可以记录成二进制文件,回放更流畅
- 运行 shell 命令:虽然 v7 增加了很多系统 API,但有些底层操作仍然需要
su -c
日常使用中,90% 以上的场景不需要 Root。