Auto.js 入门指南(八)高级控件与 UI 自动化

前言

大家好,我是鲫小鱼。是一名不写前端代码的前端工程师,热衷于分享非前端的知识,带领切图仔逃离切图圈子,欢迎关注我,微信公众号:《鲫小鱼不正经》。欢迎点赞、收藏、关注,一键三连!!

第八章:高级控件与 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 脚本与自动化逻辑分离,提升健壮性

最后感谢阅读!欢迎关注我,微信公众号:《鲫小鱼不正经》。欢迎点赞、收藏、关注,一键三连!!!

相关推荐
JiangJiang1 分钟前
🔥 面试官:Webpack 为什么能热更新?你真讲得清吗?
前端·面试·webpack
anyup21 分钟前
快崩溃了!华为应用商店已经 4 次驳回我的应用上线
前端·华为·uni-app
Qian Xiaoo35 分钟前
前后端分离开发 和 前端工程化
前端
要加油哦~1 小时前
vue · 插槽 | $slots:访问所有命名插槽内容 | 插槽的使用:子组件和父组件如何书写?
java·前端·javascript
先做个垃圾出来………1 小时前
split方法
前端
前端Hardy2 小时前
HTML&CSS:3D图片切换效果
前端·javascript
spionbo2 小时前
Vue 表情包输入组件实现代码及完整开发流程解析
前端·javascript·面试
全宝2 小时前
✏️Canvas实现环形文字
前端·javascript·canvas
lyc2333332 小时前
鸿蒙Core File Kit:极简文件管理指南📁
前端