使用无障碍技术实现自动化脚本
Android 系统原生提供 AccessibilityService 无障碍服务,设计初衷是为视障、行动不便用户提供屏幕朗读、快捷操作等辅助能力,该服务拥有读取页面 UI 树、模拟触控、监听窗口与通知事件等系统级能力,是移动端轻量化自动化最合规、门槛最低的技术路线,无需 Root 设备,仅需用户手动开启无障碍权限即可运行。不同于坐标点击、OCR 图像识别等视觉类自动化方案,无障碍方案依托页面控件固有属性定位元素,不受手机分辨率、APP 界面配色、字体大小影响,多机型兼容性更强,是日常任务自动化、APP 功能测试、重复操作替代场景的首选方案。本文从基础原理、核心 API 解析、完整脚本案例、避坑优化方案四个维度,系统讲解无障碍自动化脚本开发流程,面向普通脚本开发者、移动端测试人员,不涉及商业推广,聚焦技术落地与最佳实践。
一、无障碍核心基础:node 控件对象与 UI 树体系
冰狐所有无障碍操作都围绕node控件对象展开,手机屏幕上每一个按钮、输入框、文字、图片,在系统 UI 树中都会生成独立 node 节点,节点之间存在父子、兄弟层级关系,这是控件定位与操作的底层依据。
(一)node 核心属性解析
每个 node 对象内置一套完整属性,用于判断控件状态、获取位置信息,也是findView定位控件的核心匹配条件,关键属性分为四类:
- 文本与标识属性:
id控件资源 ID、text显示文本、className控件类名,三者是定位控件最常用标识;支持模糊匹配规则,如txt*包含文本、id$ID 后缀匹配。 - 交互状态属性:
clickable是否可点击、checked复选框选中状态、selected标签选中、enabled控件是否可用,常用于循环判断控件交互状态。 - 尺寸坐标属性:
left/top/right/bottom控件屏幕像素边界、width/height宽高,可结合gestureClick实现精准坐标手势。 - 层级关系属性:
parent父控件、prevSibling/nextSibling前后兄弟控件、数组下标直接访问子控件,无唯一 ID / 文本的控件依靠层级定位。
(二)UI 树调试工具使用方法
开发脚本前,必须借助平台 UI 树工具获取页面控件信息:登录冰狐网页端,进入「移动端 - 我的设备」,选中在线设备点击获取 UI 树,即可查看当前页面全部 node 节点,右上角根索引可切换多根界面(输入法、悬浮窗、状态栏均为独立根容器)。 调试技巧:无唯一标识的控件,在 UI 树中记录目标控件的父、子层级索引,后续通过family参数或数组下标精准抓取,解决多同类型控件混淆问题。
二、冰狐无障碍核心 API 分层详解
冰狐将无障碍函数分为控件定位、页面交互、手势操作、页面流程控制、系统事件监听五大模块,覆盖绝大多数自动化场景,下文结合官方文档说明适用场景与典型代码示例。
(一)控件定位类:自动化脚本的核心根基
定位是脚本稳定运行的关键,findView是使用率最高的接口,支持多条件组合、全局 / 局部根搜索、容错重试、筛选可点击控件等能力。
- findView:按 tag 匹配控件tag 支持多匹配规则,用
|分隔或条件@同时匹配;options 参数提供find_all全量查找、traverse_invisible检索隐藏控件、root指定根容器缩小搜索范围,failed回调可处理弹窗干扰。// 查找所有文本包含"确认"的可点击控件,包含隐藏控件 var res = findView('txt*:确认',{flag:"find_all|clickable|traverse_invisible",maxStep:8,afterWait:300}); if(res.length>0){ console.log("找到控件数量:"+res.views.length); var targetBtn = res.views[0]; } - findRoot:切换多根界面Android 页面存在多个根容器(弹窗、键盘、悬浮窗),直接全局搜索会出现控件找不到的问题,
findRoot可通过索引或文本定位目标根界面,限定搜索范围。// 定位数字键盘弹窗根容器,仅在弹窗内搜索输入按钮 var keyBoardRoot = findRoot("txt:数字键盘"); if(keyBoardRoot!=null){ var numBtn = findView("txt:5",{root:keyBoardRoot}); } - family 层级定位:无标识控件解决方案页面大量无独立 text、id 的装饰控件,可先定位相邻唯一控件,通过
family数组层级索引跳转目标节点,替代复杂的父子循环遍历,简化代码。// 找到文本“设备名”控件,取其父控件第0个子控件、第2个子控件 click("txt:设备名",{family:[0,2],click:true});
(二)基础交互操作:控件点击、输入、滚动
- click 控件点击支持原生控件点击(
click:true,依赖控件 clickable 属性)与手势模拟点击;clickCount实现双击、长按;widgetIndex指定点击第 N 个匹配控件,适配列表批量操作。// 原生点击“提交”按钮,点击后等待2秒加载页面 click("txt:提交",{click:true,afterWait:2000,maxStep:5}); - paste 文本输入统一处理输入框赋值,
type区分覆盖写入set与追加粘贴paste,无需手动唤起键盘,适配搜索框、表单填写场景。// 输入框写入测试文本 paste("cn:android.widget.EditText","自动化测试内容",{afterWait:500}); - scroll 页面滚动支持上下左右滑动,
type=2调用系统翻页,滑动更稳定;distance控制滑动比例,循环滚动列表遍历全部条目。// 列表向上滑动95%高度,滑动后等待3秒加载数据 scroll("id:list_container","up",{type:2,distance:0.95,afterWait:3000});
(三)底层手势与坐标操作
当控件无法正常定位(APP 限制无障碍读取节点),可使用纯手势函数操作屏幕坐标,支持单指、多指、自定义轨迹滑动:
- gestureClick 单点坐标点击:支持 px 像素、percent 屏幕比例单位,适配不同分辨率设备;
- multiGestureClick 多点同步点击:模拟双指缩放、多按钮同时点击;
- gesture 自定义轨迹手势:可设置每段滑动时长,模拟真人缓慢滑动,降低风控识别概率。
// 屏幕比例点击屏幕中心位置 gestureClick(0.5,0.5,{unit:"percent",duration:150});(四)页面流程封装函数:简化多步骤跳转
针对页面切换、返回上一页等重复逻辑,平台封装高集成度函数,减少重复判断代码:
- switchPage 单页面跳转:点击查找控件,校验目标页面标识判断是否跳转成功,内置重试机制;
- switchPages 批量连续切换:一次性执行多页面跳转流程,返回成功步骤数,适合多级菜单导航;
- back2Page 返回指定页面:循环调用返回键,直到页面出现目标控件,适配弹窗、多级详情页返回场景。
(五)系统监听回调函数:事件驱动自动化
区别于定时循环脚本,cbNotification通知回调、cbWindowChange窗口变化回调实现事件触发式自动化,资源占用更低,适合消息响应类场景:
cbNotification:系统收到 APP 通知自动触发,可调用openNotification跳转通知详情;cbWindowChange:页面跳转、弹窗弹出、Toast 提示时触发,实时捕获界面文本,自动拦截广告弹窗。
三、完整实战脚本:APP 表单自动填写流程
结合上述 API,编写一套通用表单自动化脚本,包含页面跳转、滚动查找、文本输入、提交、返回首页全流程,包含容错、弹窗处理逻辑,可直接修改 tag 适配各类 APP:
function main(){ // 步骤1:进入我的页面 var enterMine = switchPage("txt:我的","txt:设置",{maxStep:5,afterWait:1000}); if(enterMine.length==0){ console.log("进入我的页面失败,脚本终止"); return; } // 步骤2:滚动页面找到表单入口 scroll(null,"up",{distance:0.8,afterWait:1000}); var formBtn = findView("txt:表单填写",{flag:"clickable",maxStep:6}); if(formBtn.length==0){ back(); return; } click(formBtn.views[0],{click:true,afterWait:1500}); // 步骤3:定位输入框并填写内容 var inputBox = findView("cn:android.widget.EditText"); if(inputBox.length>0){ paste(inputBox.views[0],"测试自动化表单",{type:"set"}); } // 步骤4:勾选复选框 var checkBox = findView("txt:同意协议"); if(checkBox.length>0 && !checkBox.views[0].checked){ click(checkBox.views[0],{click:true}); } // 步骤5:提交表单 click("txt:提交",{click:true,afterWait:2000}); // 步骤6:返回首页 back2Page("txt:首页",{maxStep:10}); console.log("表单自动化流程执行完成"); } // 窗口变化监听,弹窗自动关闭 function cbWindowChange(textList,className,packageName,rawEvent){ if(textList.includes("广告")){ var closeBtn = findView("txt:关闭",{maxStep:2}); if(closeBtn.length>0) click(closeBtn.views[0]); } }四、无障碍脚本开发常见问题与优化实践
(一)控件定位失败的解决办法
- 页面存在多根界面:使用
findRoot切换弹窗、键盘根容器,限定 root 搜索范围; - 控件隐藏未检索:
findView添加traverse_invisible标识检索不可见控件; - 同文本多个控件:搭配
family层级定位、widgetIndex指定下标、region限定屏幕区域缩小匹配范围; - APP 屏蔽无障碍节点:降级使用
gestureClick坐标手势作为兜底方案。
(二)脚本稳定性优化方案
- 增加等待参数:所有操作添加
beforeWait/afterWait,适配 APP 加载动画,避免页面未渲染完成查找控件; - 配置重试机制:
findView设置maxStep自动重复搜索,无需手动写循环; - 弹窗自动拦截:利用
findView的failed回调或cbWindowChange全局监听,自动关闭广告、权限弹窗; - 拟人化操作:
click开启随机点击坐标、gesture设置滑动时长,避免固定机械操作触发 APP 风控。
(三)无障碍服务使用边界与合规提示
Android 无障碍服务原生定位是辅助残障用户,开发自动化脚本仅可用于个人自用、企业内部 APP 功能测试等合规场景,禁止用于批量营销、违规引流、破解 APP 限制等违反应用服务协议与法律法规的场景。同时新版 Android 系统对无障碍权限管控持续收紧,部分金融、社交 APP 会限制无障碍读取 UI 节点,此类场景可搭配 OCR 图像识别作为补充方案。
五、结语
相比于坐标点击、图像识别,无障碍自动化具备跨设备通用、运行稳定、资源消耗低三大优势,是移动端轻量自动化的最优技术路线。开发者在实际编写脚本时,应遵循 “优先控件属性定位、层级定位兜底、坐标手势作为最后备选” 的开发原则,配合页面等待、弹窗容错逻辑,大幅提升脚本长期挂机运行的可靠性。同时持续关注 Android 系统无障碍权限更新规则,合理、合规使用无障碍能力,规避应用限制与系统权限管控带来的脚本失效问题。
