Autox.js 控件选择器基础 text id className desc 四种属性定位
Autox.js 的核心:选择器 API
如果说无障碍服务是 Autox.js 的眼睛,那选择器 API 就是它的大脑。整个自动化体系建立在这套 API 之上——用它们来"找到"屏幕上的控件,然后对找到的控件发送动作。
选择器的四件事
所有选择器调用最后都落到这四件事:
| 操作 | 函数 | 返回 |
|---|---|---|
| 创建选择器 | text("登录") | 一个 Selector 对象 |
| 查找一个匹配 | .findOne(timeout?) | 第一个匹配的控件或 null |
| 查找全部匹配 | .find() | 所有匹配控件的数组 |
| 等待出现 | .until(timeout?) | 等待匹配控件出现,期间会自动刷新 |
四种基础属性选择器
1. text() — 按显示文字
text("确定").click();
匹配屏幕上所有显示文字为"确定"的控件。最直观、最容易用,但稳定性一般——App 改版改了文字就失效。
2. id() — 按资源 ID
id("confirm_btn").click();
// 或完整包名
id("com.example:id/confirm_btn").click();
匹配控件的 resource-id。id 是最稳定的选择器——开发者在代码里写死了,除非 App 重构或混淆,一般不会变。但注意:不是所有控件都有 id(自定义 View 可能没有、游戏引擎的控件一定没有)。
3. className() — 按类名
className("Button").click();
className("android.widget.Button").click(); // 完整类名
匹配控件的 Java 类名。Android 标准控件的类名一般是 android.widget.Button、android.widget.EditText 这样。只用短名 "Button" 会匹配所有包下叫 Button 的类。
4. desc() — 按无障碍描述
desc("登录按钮").click();
匹配 contentDescription,这是开发者为残障用户添加的无障碍描述。很多 App 没填这个字段,所以用的人不多,但如果有,稳定性和 id 差不多。
组合选择器
单个条件可能匹配到太多控件,这时可以链式叠加多个条件:
// 既是 Button 类、又显示"确定"文字
className("Button").text("确定").click();
// id 是 btn_confirm 且 desc 是确认
id("btn_confirm").desc("确认").click();
模糊匹配变体
Autox.js 的选择器还提供了模糊匹配版本:
| 精确 | 模糊 | 作用 |
|---|---|---|
text("确定") | textContains("确定") | 包含"确定"文字 |
textStartsWith("确") | 以"确"开头 | |
textEndsWith("定") | 以"定"结尾 | |
textMatches("确.定") | 正则匹配 | |
id("btn") | idContains("btn") | id 包含 |
className("Button") | classNameContains("Button") | 类名包含 |
desc("登录") | descContains("登录") | desc 包含 |
模糊匹配在不知道精确值时很有用,但优先级低于精确匹配——能用精确值时别偷懒。
从父控件查找子控件
// 从 id 为 container 的父容器中找 Button
id("container").findOne().findOne(className("Button")).click();
// 或者直接 descendants 遍历
id("container").findOne().descendants()
.filter(c => c.className() === "Button")
.forEach(c => c.click());
这招在"屏幕上有多个同名 Button,但只有某个特定容器里的那个是我要的"时特别有用。
实战代码示例
假设你要在一个登录页面自动填写并提交:
console.show();
// 等待登录页加载(最多 10 秒)
if (!text("登录").findOne(10000)) {
console.error("登录页加载超时");
exit();
}
console.log("登录页已就绪");
// 找到账号输入框并填入
let username = className("EditText").id("username_input").findOne();
if (username) {
username.setText("myaccount");
console.log("账号填写完成");
}
// 找到密码输入框并填入
let password = className("EditText").id("password_input").findOne();
if (password) {
password.setText("123456");
console.log("密码填写完成");
}
// 点击登录
let loginBtn = className("Button").text("登录").findOne();
if (loginBtn) {
loginBtn.click();
console.log("登录按钮已点击");
} else {
console.error("没找到登录按钮");
}
性能提示
选择器查找是昂贵操作(每次查找都要遍历整个控件树),注意:
- 不要在高频循环里反复调用选择器——存到变量里复用
.find()返回数组时如果只需要一个,用.findOne()更快- 长时间运行的脚本中偶尔刷新控件树(某些版本的选择器会缓存旧数据)