基础

# 基于控件的操作 基于控件的操作指的是选择屏幕上的控件,获取其信息或对其进行操作。对于一般软件而言,基于控件的操作对不同机型有很好的兼容性;但是对于游戏而言,由于游戏界面并不是由控件构成,无法采用本章节的方法,也无法使用本章节的函数。有关游戏脚本的编写,请参考《基于坐标的操作》。 基于控件的操作依赖于无障碍服务,因此最好在脚本开头使用auto()函数来确保无障碍服务已经启用。如果运行到某个需要权限的语句无障碍服务并没启动,则会抛出异常并跳转到无障碍服务界面。这样的用户体验并不好,因为需要重新运行脚本,后续会加入等待无障碍服务启动并让脚本继续运行的函数。 您也可以在脚本开头使用"auto";表示这个脚本需要无障碍服务,但是不推荐这种做法,因为这个标记必须在脚本的最开头(前面不能有注释或其他语句、空格等),我们推荐使用auto()函数来确保无障碍服务已启用。 ## auto([mode]) |参数|类型|描述| |-|-|-| |mode |string|模式| 检查无障碍服务是否已经启用,如果没有启用则抛出异常并跳转到无障碍服务启用界面;同时设置无障碍模式为mode。mode的可选值为: - fast 快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。 - normal 正常模式,默认。 如果不加mode参数,则为正常模式。 建议使用auto.waitFor()和auto.setMode()代替该函数,因为auto()函数如果无障碍服务未启动会停止脚本;而auto.waitFor()则会在在无障碍服务启动后继续运行。 示例: ``` auto("fast"); ``` 示例2: ``` auto(); ``` ## auto.waitFor() 检查无障碍服务是否已经启用,如果没有启用则跳转到无障碍服务启用界面,并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行。 ## auto.setMode(mode) |参数|类型|描述| |-|-|-| |mode |string|模式| 设置无障碍模式为mode。mode的可选值为: 1. fast 快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件查看和操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。 2. normal 正常模式,默认。 ## 设置搜索窗口 > 非官方文档内容。此内容由飞云补充 ```js // 设置搜索对象为活跃窗口 auto.setWindowFilter(function (window) { return window.active == true }) ``` 设置窗口过滤器。这个过滤器可以决定哪些窗口是目标窗口,并影响选择器的搜索。 例如:如果想要选择器在所有窗口,包括状态栏、输入法等中搜索,只需要使用如下代码: ```js // 设置搜索对象为所有窗口(不管是如何窗口,都返回true,表示在该窗口中搜索) auto.setWindowFilter(function (window) { return true }) ``` ### 相关资料 [Autojs获取支付宝,微信的控件](https://www.jianshu.com/p/2c7f2c2cbf78) ## 检测是否打开无障碍权限 > 非官方例子 ```js // 检测是否打开无障碍权限 if (!floaty.checkPermission()) { toast("未打开无障碍权限!请打开无障碍权限。"); floaty.requestPermission(); } else { toast("无障碍权限已打开!"); }; ``` # SimpleActionAutomator SimpleActionAutomator提供了一些模拟简单操作的函数,例如点击文字、模拟按键等。这些函数可以直接作为全局函数使用。 ## setText([i, ]text) |参数|类型|描述| |-|-|-| |i|number|表示要输入的为第i + 1个输入框| |text |string|要输入的文本| **返回是否输入成功**。当找不到对应的文本框时返回false。 不加参数i则会把所有输入框的文本都置为text。例如setText("测试")。 这里的输入文本的意思是,把输入框的文本置为text,而不是在原来的文本上追加。 ## input([i, ]text) |参数|类型|描述| |-|-|-| |i|number|表示要输入的为第i + 1个输入框| |text |string|要输入的文本| 返回是否输入成功。当找不到对应的文本框时返回false。 不加参数i则会把所有输入框的文本追加内容text。例如input("测试")。 > 如果输入框有预置文本,input会将预留文本也追加到text ## click(text[, i]) |参数|类型|描述| |-|-|-| |text |string|要点击的文本| |i|number|如果相同的文本在屏幕中出现多次,则i表示要点击第几个文本, i从0开始计算| 返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 该函数可以点击大部分包含文字的按钮。 例如微信主界面下方的"微信", "联系人", "发现", "我"的按钮。 **通常与while同时使用以便点击按钮直至成功**。例如: ```js while(!click("扫一扫")); ``` 当不指定参数i时则会尝试点击屏幕上出现的所有文字text并返回是否全部点击成功。 i是从0开始计算的, 也就是, click("啦啦啦", 0)表示点击屏幕上第一个"啦啦啦", click("啦啦啦", 1)表示点击屏幕上第二个"啦啦啦"。 > 文本所在区域指的是,从文本处向其父视图寻找,直至发现一个可点击的部件为止。 ## click(left, top, bottom, right) |参数|类型|描述| |-|-|-| |left |number|要点击的长方形区域左边与屏幕左边的像素距离| |top |number|要点击的长方形区域上边与屏幕上边的像素距离| |bottom |number|要点击的长方形区域下边与屏幕下边的像素距离| |right |number|要点击的长方形区域右边与屏幕右边的像素距离| 注意,该函数一般只用于录制的脚本中使用,在自己写的代码中使用该函数一般不要使用该函数。 点击在指定区域的控件。当屏幕中并未包含与该区域严格匹配的区域,或者该区域不能点击时返回false,否则返回true。 有些按钮或者部件是图标而不是文字(例如发送朋友圈的照相机图标以及QQ下方的消息、联系人、动态图标),这时不能通过click(text, i)来点击,可以通过描述图标所在的区域来点击。left, bottom, top, right描述的就是点击的区域。 至于要定位点击的区域,可以在悬浮窗使用布局分析工具查看控件的bounds属性。 通过无障碍服务录制脚本会生成该语句。 ## longClick(text[, i])) |参数|类型|描述| |-|-|-| |text |string|要长按的文本| |i|number|如果相同的文本在屏幕中出现多次,则i表示要点击第几个文本, i从0开始计算| 返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 当不指定参数i时则会尝试点击屏幕上出现的所有文字text并返回是否全部长按成功。 ## scrollUp([i]) |参数|类型|描述| |-|-|-| |i|number|要滑动的控件序号| 找到第i+1个可滑动控件上滑或左滑。返回是否操作成功。屏幕上没有可滑动的控件时返回false。 另外不加参数时scrollUp()会寻找面积最大的可滑动的控件上滑或左滑,例如微信消息列表等。 参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如scrollUp(0)为滑动第一个可滑动控件。 ## scrollDown([i]) |参数|类型|描述| |-|-|-| |i|number|要滑动的控件序号| 找到第i+1个可滑动控件下滑或右滑。返回是否操作成功。屏幕上没有可滑动的控件时返回false。 另外不加参数时scrollUp()会寻找面积最大的可滑动的控件下滑或右滑。 参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如scrollUp(0)为滑动第一个可滑动控件。 ## 实例 ```js //搜索进入微信运动排行榜 //此代码由飞云脚本圈原创(www.feiyunjs.com) var myAPP = {}; // 唯一的全局变量myAPP myAPP.packageName = "com.tencent.mm"; //包名 //启动APP launch(myAPP.packageName); object = className('android.widget.ImageView').id("jb").depth('9').findOne(5000); //如果找到控件则点击 if (object != null) { log("找到搜索") // sleep(2000); //等待搜索建立 // 进入搜索 let b = object.bounds(); if (click(b.centerX(), b.centerY())) { // log(b.centerX()) // toast("点击成功"); sleep(1000); // 这里需要输入两次 input('飞云'); setText('微信运动'); // 尋找公众号 object = className('android.widget.ImageView').id("qk").depth('12').findOne(2000); //如果找到控件则点击 if (object != null) { // 進入公众号 b = object.bounds(); if (click(b.centerX(), b.centerY())) { object = className('android.widget.LinearLayout').id("amy").depth('12').findOne(2000); if (object != null) { log("找到排行榜") b = object.bounds(); if (click(b.centerX(), b.centerY())) { // log(b.centerX()) toast("点击成功"); sleep(3000); }; }; sleep(1000); } else { toast("点击失败"); }; } else { //否则提示没有找到 toast("操作失败"); }; } else { toast("点击失败"); }; //如果使用root权限,则用 Tap(b.centerX(), b.centerY()); } else { //否则提示没有找到 toast("没有找到搜索"); }; ```