基于控件的操作
基于控件的操作指的是选择屏幕上的控件,获取其信息或对其进行操作。对于一般软件而言,基于控件的操作对不同机型有很好的兼容性;但是对于游戏而言,由于游戏界面并不是由控件构成,无法采用本章节的方法,也无法使用本章节的函数。有关游戏脚本的编写,请参考《基于坐标的操作》。
基于控件的操作依赖于无障碍服务,因此最好在脚本开头使用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 的可选值为:
fast
快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件查看和操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。normal
正常模式,默认。
SimpleActionAutomator
稳定性: 稳定
SimpleActionAutomator 提供了一些模拟简单操作的函数,例如点击文字、模拟按键等。这些函数可以直接作为全局函数使用。
click(text[, i])
text
{string} 要点击的文本i
{number} 如果相同的文本在屏幕中出现多次,则 i 表示要点击第几个文本, i 从 0 开始计算
返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回 false,否则返回 true。
该函数可以点击大部分包 含文字的按钮。例如微信主界面下方的"微信", "联系人", "发现", "我"的按钮。
通常与 while 同时使用以便点击按钮直至成功。例如:
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)
为滑动第一个可滑动控件。
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("测试")
。
UiSelector
UiSelector 即选择器,用于通过各种条件选取屏幕上的控件,再对这些控件进行点击、长按等动作。这里需要先简单介绍一下控件和界面的相关知识。
一般软件的界面是由一个个控件构成的,例如图片部分是一个图片控件(ImageView),文字部分是一个文字控件(TextView);同时,通过各种布局来决定各个控件的位置,例如,线性布局(LinearLayout)里面的控件都是按水平或垂直一次叠放的,列表布局(AbsListView)则是以列表的形式显示控件。
控件有各种属性,包括文本(text), 描述(desc), 类名(className), id 等等。我们通常用一个控件的属性来找到这个控件,例如,想要点击 QQ 聊天窗口的"发送"按钮,我们就可以通过他的文本属性为"发送"来找到这个控件并点击他,具体代码为:
var sendButton = text("发送").findOne();
sendButton.click();
在这个例子中, text("发送")
表示一个条件(文本属性为"发送"),findOne()
表示基于这个条件找到一个符合条件的控件,从而我们可以得到发送按钮 sendButton,再执行sendButton.click()
即可点击"发送"按钮。
用文本属性来定位按钮控件、文本控件通常十分有效。但是,如果一个控件是图片控件,比如 Auto.js 主界面右上角的搜索图标,他没有文本属性,这时需要其他属性来定位他。我们如何查看他有什么属性呢?首先打开悬浮窗和无障碍服务,点击蓝色的图标(布局分析), 可以看到以下界面:
之后我们点击搜索图标,可以看到他有以下属性:
我们注意到这个图标的 desc(描述)属性为"搜索",那么我们就可以通过 desc 属性来定位这个控件,得到点击搜索图标的代码为:
desc("搜索").findOne().click();
可能心细的你可能注意到了,这个控件还有很多其他的属性,例如 checked, className, clickable 等等,为什么不用这些属性来定位搜索图标呢?答案是,其他控件也有这些值相同的属性、尝试一下你就可以发现很多其他控件的 checked 属性和搜索控件一样都是false
,如果我们用checked(false)
作为条件,将会找到很多控件,而无法确定哪一个是搜索图标。因此,要找到我们想要的那个控件,选择器的条件通常需要是可唯一确定控件的。我们通常用一个独一无二的属性来定位一个控件,例如这个例子中就没有其他控件的 desc(描述)属性为"搜索"。
另外,对于这个搜索图标而言,id 属性也是唯一的,我 们也可以用id("action_search").findOne().click()
来点击这个控件。如果一个控件有 id 属性,那么这个属性很可能是唯一的,除了以下几种情况:
- QQ 的控件的 id 属性很多都是"name",也就是在 QQ 界面难以通过 id 来定位一个控件
- 列表中的控件,比如 QQ 联系人列表,微信联系人列表等
尽管 id 属性很方便,但也不总是最方便的,例如对于微信和网易云音乐,每次更新他的控件 id 都会变化,导致了相同代码对于不同版本的微信、网易云音乐并不兼容。
除了这些属性外,主要还有以下几种属性:
className
类名。类名表示一个控件的类型,例如文本控件为"android.widget.TextView", 图片控件为"android.widget.ImageView"等。packageName
包名。包名表示控件所在的应用包名,例如 QQ 界面的控件的包名为"com.tencent.mobileqq"。bounds
控件在屏幕上的范围。drawingOrder
控件在父控件的绘制顺序。indexInParent
控件在父控件的位置。clickable
控件是否可点击。longClickable
控件是否可长按。checkable
控件是否可勾选。checked
控件是否可已勾选。scrollable
控件是否可滑动。selected
控件是否已选择。editable
控件是否可编辑。visibleToUser
控件是否可见。enabled
控件是否已启用。depth
控件的布局深度。
有时候只靠一个属性并不能唯一确定一个控件,这时需要通过属性的组合来完成定位,例如className("ImageView").depth(10).findOne().click()