前言
大家好,我是鲫小鱼。是一名不写前端代码
的前端工程师,热衷于分享非前端的知识,带领切图仔逃离切图圈子,欢迎关注我,微信公众号:《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!
第八章:高级控件与 UI 自动化
一、理论讲解:UI 自动化的核心与难点
在移动端自动化中,UI 控件的识别与操作是最核心也是最具挑战性的部分。高级控件操作不仅仅是简单的点击、输入,还包括复杂的层级遍历、动态控件适配、列表滚动、弹窗处理、表单自动填写、批量操作等。
1.1 高级控件的常见类型
- 列表(ListView、RecyclerView、ScrollView)
- 表单(多输入框、下拉框、单选/多选框)
- 弹窗(Dialog、PopupWindow、Alert)
- 动态生成控件(如广告、推荐位、动态加载内容)
- 嵌套布局、复杂层级控件
1.2 UI 自动化的难点
- 控件层级深、结构复杂,难以唯一定位
- 动态控件 id/文本/属性经常变化
- 列表懒加载、分页、滚动加载
- 弹窗、广告、遮挡层干扰
- 多语言、多分辨率、多品牌适配
1.3 Auto.js 高级控件操作能力
- 支持多种查找方式:text、desc、id、className、textMatches、descMatches、bounds、index 等
- 支持 find、findOne、exists、parent、child、sibling、click、longClick、setText、scrollForward、scrollBackward 等
- 支持正则、模糊查找、批量操作、属性获取与设置
- 支持 UI 脚本自定义界面与自动化结合
二、基础用法与进阶代码示例
2.1 列表控件的遍历与操作
javascript
// 遍历 ListView 所有项并输出文本
var list = className("android.widget.ListView").findOne();
if (list) {
for (let i = 0; i < list.childCount(); i++) {
let item = list.child(i);
log("第" + (i+1) + "项:" + item.text());
}
}
// 滚动查找目标项并点击
function scrollAndClick(targetText) {
var list = className("android.widget.ListView").findOne();
for (let i = 0; i < 20; i++) {
let item = text(targetText).findOne(1000);
if (item) {
item.click();
toast("已点击:" + targetText);
return true;
}
list.scrollForward();
sleep(500);
}
toast("未找到目标项");
return false;
}
2.2 RecyclerView/ScrollView 动态加载
javascript
// 滚动 RecyclerView 查找并点击目标
function scrollRecyclerAndClick(targetText) {
var rv = className("androidx.recyclerview.widget.RecyclerView").findOne();
for (let i = 0; i < 30; i++) {
let item = text(targetText).findOne(1000);
if (item) {
item.click();
toast("已点击:" + targetText);
return true;
}
rv.scrollForward();
sleep(500);
}
toast("未找到目标项");
return false;
}
2.3 表单自动填写与批量输入
javascript
// 自动填写表单
var inputs = className("android.widget.EditText").find();
inputs.forEach((input, i) => {
input.setText("内容" + (i+1));
});
// 批量选择单选/多选框
className("android.widget.CheckBox").find().forEach(cb => {
if (!cb.checked()) cb.click();
});
2.4 弹窗与对话框自动处理
javascript
// 自动关闭常见弹窗
["关闭", "取消", "我知道了", "忽略"].forEach(txt => {
let btn = text(txt).findOne(500);
if (btn) btn.click();
});
// 检查并输入验证码弹窗
if (textMatches(/验证码/).exists()) {
let input = className("android.widget.EditText").findOne();
input.setText("123456");
click("确定");
}
2.5 动态控件与属性适配
javascript
// 动态 id/文本适配
var btn = id("btn_ok").exists() ? id("btn_ok").findOne() : textMatches(/(确定|OK|Yes)/).findOne();
btn && btn.click();
// 获取控件属性
var node = text("提交").findOne();
log("是否可见:" + node.visibleToUser());
log("是否可点击:" + node.clickable());
log("控件文本:" + node.text());
2.6 嵌套布局与复杂层级遍历
javascript
// 遍历 FrameLayout 下所有 Button
var frame = className("android.widget.FrameLayout").findOne();
frame.children().forEach(child => {
if (child.className() === "android.widget.Button") {
log("按钮文本:" + child.text());
}
});
// 递归查找所有 EditText
function findAllEditText(node, arr=[]) {
if (!node) return arr;
if (node.className() === "android.widget.EditText") arr.push(node);
for (let i = 0; i < node.childCount(); i++) {
findAllEditText(node.child(i), arr);
}
return arr;
}
var allInputs = findAllEditText(className("android.widget.LinearLayout").findOne());
log("共找到输入框:" + allInputs.length);
2.7 正则与模糊查找
javascript
// 正则查找所有"领取"按钮并点击
textMatches(/(领取|Claim|Get)/).find().forEach(btn => btn.click());
// 模糊查找包含"红包"的控件
textContains("红包").find().forEach(node => log(node.text()));
2.8 UI 脚本与自动化结合
javascript
"ui";
ui.layout(
<vertical>
<text textSize="22sp" textColor="#222">自动化表单填写</text>
<input id="input1" hint="请输入A" />
<input id="input2" hint="请输入B" />
<button id="btn" text="自动填写" />
</vertical>
);
ui.btn.on("click", () => {
ui.input1.setText("自动A");
ui.input2.setText("自动B");
toast("已自动填写");
});
三、实战项目:自动化表单批量填写与提交
3.1 需求分析
- 自动遍历页面所有表单输入框,批量填写内容
- 自动选择所有多选框、单选框
- 自动点击"提交"按钮
- 支持动态表单、弹窗、验证码等复杂场景
- 支持日志输出、异常处理、结果反馈
3.2 项目结构
plaintext
autojs-formfill/
├── main.js
├── modules/
│ ├── formfill.js
│ └── logger.js
├── logs/
│ └── formfill.log
└── README.md
3.3 formfill.js 代码
javascript
// modules/formfill.js
const logger = require("./logger.js");
function run(formData) {
logger.log("开始自动填写表单");
// 填写输入框
var inputs = className("android.widget.EditText").find();
inputs.forEach((input, i) => {
input.setText(formData[i] || "内容" + (i+1));
});
// 选择所有多选框
className("android.widget.CheckBox").find().forEach(cb => {
if (!cb.checked()) cb.click();
});
// 选择所有单选框
className("android.widget.RadioButton").find().forEach(rb => {
if (!rb.checked()) rb.click();
});
// 自动点击"提交"按钮
let btn = textMatches(/(提交|保存|确定)/).findOne(3000);
if (btn) {
btn.click();
logger.log("已点击提交");
} else {
logger.log("未找到提交按钮");
}
}
module.exports = { run };
3.4 日志模块 modules/logger.js
javascript
// modules/logger.js
function log(msg) {
let line = `[${new Date().toLocaleTimeString()}] ${msg}`;
files.append("../logs/formfill.log", line + "\n");
toast(msg);
}
module.exports = { log };
3.5 main.js 代码
javascript
// main.js
const formfill = require("./modules/formfill.js");
const logger = require("./modules/logger.js");
// 示例表单数据
let formData = ["张三", "123456", "备注内容"];
// 启动自动化表单填写
formfill.run(formData);
// 日志输出
logger.log("表单自动化流程结束");
四、分步详解与进阶技巧
4.1 复杂层级控件的递归遍历
- 递归查找所有输入框、按钮、列表项
- 支持多层嵌套、动态生成控件
4.2 动态控件适配与容错
- 动态 id/文本/属性适配,兼容不同版本
- 正则、模糊查找提升适配率
- 异常捕获,防止崩溃
4.3 列表懒加载与滚动加载
- 自动滚动加载更多内容,批量操作
- 支持分页、下拉刷新、上拉加载
4.4 弹窗与广告自动处理
- 检查并自动关闭弹窗、广告、遮挡层
- 支持多种弹窗类型、文本、控件适配
4.5 表单自动化与数据驱动
- 支持从文件/网络读取表单数据,批量自动填写
- 支持结果校验、异常重试、日志记录
4.6 UI 脚本与自动化协同
- UI界面与自动化脚本联动,提升交互体验
- 支持参数配置、结果展示、日志查看
4.7 多语言、多分辨率适配
- 支持多语言控件文本、不同分辨率/品牌适配
- 合理使用 dp/sp 单位,避免硬编码像素
4.8 高级控件操作性能优化
- 控件查找加超时,避免死循环
- 批量操作分批处理,减少卡顿
- 日志分级输出,开发阶段多输出,正式运行时降级
- 异步处理耗时操作,提升主流程响应
- 定期清理无用变量、释放资源,降低内存占用
五、常见问题与解决方案
问题 | 解决方案 |
---|---|
控件找不到/点击无效 | 检查控件属性、增加等待时间、尝试多种查找方式 |
列表项无法滚动/加载 | 检查列表类型、使用 scrollForward/scrollBackward |
动态控件 id/文本变化 | 用正则、模糊查找、属性适配提升兼容性 |
弹窗/广告遮挡 | 增加弹窗检测与自动关闭逻辑 |
表单填写失败/内容丢失 | 检查输入框属性、输入方法、异常捕获 |
多语言/多分辨率适配问题 | 用 textMatches、textContains、dp/sp 单位适配 |
脚本卡顿/崩溃 | 优化控件查找、批量操作、加异常捕获 |
UI 脚本与自动化冲突 | 合理拆分主流程与 UI 逻辑,避免互相阻塞 |
六、性能优化建议
- 控件查找建议加超时,避免死循环
- 批量操作分批处理,减少卡顿
- 动态控件适配,提升兼容性
- 日志分级输出,开发阶段多输出,正式运行时降级
- 异步处理耗时操作,提升主流程响应
- 定期清理无用变量、释放资源,降低内存占用
- 合理 sleep,避免无效等待
- 多语言、多分辨率适配,提升用户体验
- UI 脚本与自动化逻辑分离,提升健壮性
最后感谢阅读!欢迎关注我,微信公众号:
《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!!