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 脚本与自动化逻辑分离,提升健壮性

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

相关推荐
魔云连洲5 分钟前
深入解析:Object.prototype.toString.call() 的工作原理与实战应用
前端·javascript·原型模式
JinSo14 分钟前
alien-signals 系列 —— 认识下一代响应式框架
前端·javascript·github
开心不就得了20 分钟前
Glup 和 Vite
前端·javascript
szial22 分钟前
React 快速入门:菜谱应用实战教程
前端·react.js·前端框架
西洼工作室28 分钟前
Vue CLI为何不显示webpack配置
前端·vue.js·webpack
黄智勇1 小时前
xlsx-handlebars 一个用于处理 XLSX 文件 Handlebars 模板的 Rust 库,支持多平台使
前端
brzhang2 小时前
为什么 OpenAI 不让 LLM 生成 UI?深度解析 OpenAI Apps SDK 背后的新一代交互范式
前端·后端·架构
brzhang3 小时前
OpenAI Apps SDK ,一个好的 App,不是让用户知道它该怎么用,而是让用户自然地知道自己在做什么。
前端·后端·架构
Lei活在当下3 小时前
【业务场景架构实战】7. 多代智能手表适配:Android APP 表盘编辑页的功能驱动设计
android·设计模式·架构
井柏然4 小时前
前端工程化—实战npm包深入理解 external 及实例唯一性
前端·javascript·前端工程化