从一部手机到一次可运行的脚本:冰狐自动化流程拆解
自动化脚本这件事,难的地方往往不在“写代码”本身。真正消耗时间的,是设备连不上、控件定位不到、脚本在调试模式跑得好好的到了发布模式却罢工。冰狐把整条链路拆成了几个可以分别处理的阶段,每个阶段都有对应的页面和函数,按它的顺序走,至少不会在环境问题上反复绕圈。
先让手机进入可调试的状态
脚本能不能跑起来,第一道门槛不在代码,在设备。需要在 Android 手机上安装冰狐客户端并登录,然后打开调试模式。调试模式和发布模式的区别是硬性的:调试模式下只能运行调试版本的脚本,发布模式下只能运行部署后的版本。如果后面发现改了代码但手机上的行为没变,多半是模式没对上。
开启调试模式的操作在客户端里完成,连续点击头像区域可以在两种模式之间切换,切换成功后标题旁会显示 prod-dev 之类的标记。无障碍权限也需要在这个阶段打开,因为后面绝大多数定位和操作函数都依赖它。冰狐的无障碍函数封装了 Android 原生的辅助接口,把 findView、click、paste 这些操作做成了可以直接调用的同步函数,省掉了自己处理 AccessibilityNodeInfo 的麻烦。
脚本从哪来:两条路,可以混着走
冰狐没有规定你必须从零手写 JS。网页端的「智能搭建脚本」走的是一条可视化路线:在「移动端」/「智能搭建脚本」中新建构建,按业务逻辑选择模块、配置参数,编译后自动生成对应的 JS 脚本。常用模块覆盖了点击、滑动、循环、条件判断这些高频操作,对于流程固定的任务,用这条路线把骨架搭出来,再手动补细节,效率往往比纯手写高。
另一条路是直接写 JS。在「移动端脚本」里新建脚本,在线或离线都可以,编辑器就是网页端的 IDE。冰狐的 JS 是 ECMAScript 的一个子集,没有 === 和 !==,比较一律用 == 和 !=,但对数组、对象、for...of 这些常用结构的支持是完整的。脚本的入口是 main 函数,所有逻辑从那里开始执行。
两条路并不互斥。实际开发中更常见的做法是:用智能搭建把页面跳转和循环框架生成出来,然后在生成的脚本里手动插入 findView 和 click 来处理那些模块覆盖不到的边缘交互。
定位:先找到,才能谈操作
冰狐把自动化脚本的技术骨架概括为三件事:定位目标元素、操作目标元素、输入文本数据。定位是地基。findView 是最核心的函数,通过控件的 id、text 或 className 来匹配,返回一个包含 tag 和 views 的 JSON 对象。views 是 node 数组,默认只返回第一个匹配项;如果页面上有多个同类控件需要逐个处理,要加上 {flag: 'find_all'} 把全部结果拿回来。
findView 的 tag 语法比看上去灵活。txt: 是精确匹配文本,txt*: 是包含匹配;id: 精确匹配 id,id$: 匹配 id 结尾,id^: 匹配开头,id*: 匹配包含。多个 tag 用 | 分隔表示“或”,用 @ 连接表示“且”。比如 findView('txt:确定@cn:android.widget.Button') 只会命中文本为“确定”且类名是按钮的那个控件。
找不到控件时,先别急着改代码。网页端「我的设备」里有一个“获取 UI 树”的入口,点开可以看到当前页面所有控件的属性快照,id、text、className、clickable、坐标都在里面。很多“定位不到”的问题,打开 UI 树看一眼就会发现目标控件的文本其实是空字符串,或者 id 里带有动态后缀,这时候就要把 txt: 换成 id^: 或者 id*: 来适配。
操作:点击、滑动、输入
定位之后的操作函数都接受两种参数形式:tag 字符串,或者直接传入 findView 返回的 node 对象。后者更精确,也少一次搜索开销。
click 的 options 里有一个值得注意的字段:click。默认是 false,表示使用手势模拟点击;设为 true 时会调用控件原生的 performClick,前提是控件的 clickable 属性为 true,或者它的某个祖先控件可点击。原生点击在某些对触摸事件敏感的 App 上更稳,但如果目标控件本身不可点击,就会直接失败,这时候退回手势模拟反而能奏效。
文本输入用 paste,type 可选 'set' 或 'paste'。'set' 走控件的文本设置接口,'paste' 走剪贴板粘贴。有些输入框对其中一种方式不响应,两种都备着,试一次就知道该用哪个。
滑动有两个层次。scroll 针对的是可滚动容器,传控件 tag 和方向(up / down / left / right),distance 用比例控制幅度,duration 控制速度,适合列表翻页这类结构化的滚动。gesture 和 gestureClick 则是自由坐标操作:gestureClick(x, y, {unit:'percent', duration:100}) 可以在屏幕任意位置落一个点,unit 支持 px、dp 和 percent,用百分比坐标写出来的脚本不会因为换了一台分辨率不同的手机就偏到屏幕外面去。
数据输入:UI 和自定义数据,选后者的时候更多
脚本需要的参数,比如搜索关键词、账号列表、目标页面的判定文本,有两种注入方式。一是做一个手机端的 UI,让使用者在设备上填写;二是在网页端「管理中心」/「自定义数据」里提前配置好,脚本里用 getCustomData 直接读取。
冰狐的文档里明确倾向于第二种:如果是输入数据、参数之类的需求,自定义数据比 UI 输入效率更高,设备数量越多,差距越明显。getCustomData 支持第二个参数作为默认值,在配置项缺失时脚本不会因为拿到 null 就直接抛异常:
javascript
var keyword = getCustomData('search_keyword', '默认词');
这样在网页端改一个值,所有设备的脚本同时生效,不需要逐台去点 UI。
调试、部署和运行:三个动作别混在一起
脚本写完,在网页端编辑器里点“执行”,选设备,就可以在手机上看到实际效果。调试过程中善用 console.log,冰狐的日志面板会按时间顺序把输出列出来,findView 返回的 views.length、控件的 left / top / width / height 都可以打出来看。
调试通过之后,关键的一步是“部署”。部署不是“保存”,它是把调试版本同步到发布版。在「移动端脚本」中选中脚本,点“部署”,发布版才会被更新。如果手机当前处于发布模式,你运行的永远是上一次部署的版本,调试版再新也碰不到。反过来说,如果希望在调试模式下反复迭代而不影响正在跑的设备,就不要急着部署。
运行的触发方式有三种:网页端选中脚本点“执行”并选择设备;手机上直接点“点击这里启动设备”;或者提前设置好默认脚本,让设备在启动时自动加载。默认脚本的优先级是:设备默认脚本覆盖子用户默认脚本,子用户默认脚本覆盖主用户默认脚本。
脚本之外的扩展:定时、网络和微服务
冰狐的 setTimeout / setInterval / setCronTask 提供了脚本内部的时序控制。setTimeout 只执行一次,setInterval 周期性执行直到 clearInterval,setCronTask 则用 cron 表达式按日历规则调度。有一个容易踩的坑:这些定时函数的文档里反复标注,不要点编辑器右上角的“调试执行”按钮来测试定时逻辑,要在移动端脚本里点“执行”来运行。调试执行的上下文和真实移动端执行不完全一样,定时器可能根本不会按预期触发。
如果脚本需要调接口拉数据或者上报结果,冰狐网络模块提供了 httpGet 和 httpPost,都是同步阻塞调用,返回对象统一带 state 和 data 两个字段:state === 'success' 时 data 是响应文本,failed 时 data 是错误原因。同步阻塞意味着不需要处理回调嵌套,脚本按行往下读就是执行顺序。
再往上走,如果后端需要按设备、按用户分发不同的参数或收集执行结果,可以在网页端「微服务」里建接口和数据库,用 JS 写服务端逻辑,移动端脚本通过微服务接口读写数据。微服务不是必选项,但当设备数量从一两台变成十几台、需要集中管理状态的时候,把共享逻辑从移动端抽到微服务里,脚本本身会清爽很多。
一条合理的顺序
如果从头开始一个冰狐脚本项目,把顺序控制在下面这条线上,大部分返工可以提前避开:先把设备调到调试模式、打开无障碍;打开 UI 树把目标页面的控件属性摸一遍,确定用 txt:、id: 还是 id^: 来定位;用智能搭建或手写 JS 把 findView → click / paste / scroll 的基本链路跑通;把可变参数抽到自定义数据里;调试模式验证通过后,部署,切发布模式,在真实触发条件下再跑一遍;最后按需挂上定时任务或微服务调用。每一步单独验证,比把所有东西堆在一起再调,要省时间得多。
本文系统拆解冰狐自动化脚本的完整开发流程,涵盖设备调试模式配置、无障碍权限启用、可视化与手写双路径脚本生成、基于tag语法的精准控件定位、手势/原生点击、滑动与文本输入操作、自定义数据注入、调试-部署-运行三阶段分离、定时任务与网络请求同步调用,以及微服务扩展。强调各环节顺序性与验证闭环,提升脚本稳定性与可维护性。

260

被折叠的 条评论
为什么被折叠?



