基础

# 基于控件的操作 基于控件的操作指的是选择屏幕上的控件,获取其信息或对其进行操作。对于一般软件而言,基于控件的操作对不同机型有很好的兼容性;但是对于游戏而言,由于游戏界面并不是由控件构成,无法采用本章节的方法,也无法使用本章节的函数。有关游戏脚本的编写,请参考《基于坐标的操作》。 基于控件的操作依赖于无障碍服务,因此最好在脚本开头使用`auto()`函数来确保无障碍服务已经启用。如果运行到某个需要权限的语句无障碍服务并没启动,则会抛出异常并跳转到无障碍服务界面。这样的用户体验并不好,因为需要重新运行脚本,后续会加入等待无障碍服务启动并让脚本继续运行的函数。 您也可以在脚本开头使用`"auto";`表示这个脚本需要无障碍服务,但是不推荐这种做法,因为这个标记必须在脚本的最开头(前面不能有注释或其他语句、空格等),我们推荐使用`auto()`函数来确保无障碍服务已启用。 ## 检查无障碍服务 | auto(mode) | 函数名 | 返回值 | 备注 | | ---------- | :------: | ------------------------------------------------------------ | | auto() | | 检查无障碍服务是否已经启用,如果没有启用则抛出异常并跳转到无障碍服务启用界面; | | **参数名** | **类型** | | | mode | 字符串 | 无障碍模式,有两种模式可以选择,快速模式可以适当提高操作速度,与稳定模式类似 | auto(mode) * `mode` {string} 模式 检查无障碍服务是否已经启用,如果没有启用则抛出异常并跳转到无障碍服务启用界面;同时设置无障碍模式为mode。mode的可选值为: * `fast` 快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。 * `normal` 正常模式,默认。 如果不加mode参数,则为正常模式。 建议使用`auto.waitFor()`和`auto.setMode()`代替该函数,因为`auto()`函数如果无障碍服务未启动会停止脚本;而`auto.waitFor()`则会在在无障碍服务启动后继续运行。 示例: ``` auto("fast"); ``` 示例2: ``` auto(); ``` ## 检查无障碍服务 | auto.waitFor() | 函数名 | 返回值 | 备注 | | -------------- | :----: | ------------------------------------------------------------ | | auto.waitFor() | | 检查无障碍服务是否已经启用,如果没有启用则跳转到无障碍服务启用界面,并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行。 | auto.waitFor() 检查无障碍服务是否已经启用,如果没有启用则跳转到无障碍服务启用界面,并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行。 因为该函数是阻塞的,因此除非是有协程特性,否则不能在ui模式下运行该函数,建议在ui模式下使用`auto()`函数。 ## 设置无障碍模式为mode | auto.setMode() | 函数名 | 返回值 | 备注 | | -------------- | :------: | ---------------------- | | auto.setMode() | | 设置无障碍模式为mode; | | **参数名** | **类型** | | | mode | 字符串 | 无障碍模式 | auto.setMode(mode) * `mode` {string} 模式 设置无障碍模式为mode。mode的可选值为: * `fast` 快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件查看和操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。 * `normal` 正常模式,默认。 ## 启用有关automator |auto.setFlags(flags) | 函数名 | 返回值 | 备注 | | --------------- | :-----------: | ------------------------------ | | auto.setFlags() | | 启用有关automator的一些特性。 | | **参数名** | **类型** | | | flags | 字符串\\|Array | 一些标志,来启用和禁用某些特性 | auto.setFlags(flags) **[v4.1.0新增]** * `flags` {string} | {Array} 一些标志,来启用和禁用某些特性,包括: * `findOnUiThread` 使用该特性后,选择器搜索时会在主进程进行。该特性用于解决线程安全问题导致的次生问题,不过目前貌似已知问题并不是线程安全问题。 * `useUsageStats` 使用该特性后,将会以"使用情况统计"服务的结果来检测当前正在运行的应用包名(需要授予"查看使用情况统计"权限)。如果觉得currentPackage()返回的结果不太准确,可以尝试该特性。 * `useShell` 使用该特性后,将使用shell命令获取当前正在运行的应用的包名、活动名称,但是需要root权限。 启用有关automator的一些特性。例如: ``` auto.setFlags(["findOnUiThread", "useShell"]); ``` ## 获取无障碍服务 | auto.service | 函数名 | 返回值 | 备注 | | -------------- | :----: | ------------------------------------------------------ | | auto.service() | | 获取无障碍服务。如果无障碍服务没有启动,则返回`null`。 | auto.service **[v4.1.0新增]** * [AccessibilityService](https://developer.android.com/reference/android/accessibilityservice/AccessibilityService) 获取无障碍服务。如果无障碍服务没有启动,则返回`null`。 参见[AccessibilityService](https://developer.android.com/reference/android/accessibilityservice/AccessibilityService)。 ## 获取当前所有窗口 | auto.windows | 函数名 | 返回值 | 备注 | | -------------- | :----: | ------------------------------------------------------------ | | auto.windows() | Array | 当前所有窗口([AccessibilityWindowInfo](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo))的数组,可能包括状态栏、输入法、当前应用窗口,弹出窗口、悬浮窗、分屏应用窗口等。可以分别获取每个窗口的布局信息。 | auto.windows **[v4.1.0新增]** * {Array} 当前所有窗口([AccessibilityWindowInfo](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo))的数组,可能包括状态栏、输入法、当前应用窗口,弹出窗口、悬浮窗、分屏应用窗口等。可以分别获取每个窗口的布局信息。 该函数需要Android 5.0以上才能运行。 ## 获取当前窗口布局元素 | auto.root | 函数名 | 返回值 | 备注 | | ----------- | :----: | ------------------------------------------------------------ | | auto.root() | 布尔型 | 当前窗口的布局根元素。如果无障碍服务未启动或者WindowFilter均返回false,则会返回`null`。 | auto.root **[v4.1.0新增]** * {UiObject} 当前窗口的布局根元素。如果无障碍服务未启动或者WindowFilter均返回false,则会返回`null`。 如果不设置windowFilter,则当前窗口即为活跃的窗口(获取到焦点、正在触摸的窗口);如果设置了windowFilter,则获取的是过滤的窗口中的第一个窗口。 如果系统是Android5.0以下,则始终返回当前活跃的窗口的布局根元素。 ## 获取当前活跃窗口布局元素 | auto.rootInActiveWindow | 函数名 | 返回值 | 备注 | | ------------------------- | :------: | ------------------------------------------------------------ | | auto.rootInActiveWindow() | UiObject | 当前活跃的窗口(获取到焦点、正在触摸的窗口)的布局根元素。如果无障碍服务未启动则为`null` | auto.rootInActiveWindow **[v4.1.0新增]** * {UiObject} 当前活跃的窗口(获取到焦点、正在触摸的窗口)的布局根元素。如果无障碍服务未启动则为`null`。 ## 设置窗口过滤器 | auto.setWindowFilter(filter) | 函数名 | 返回值 | 备注 | | ---------------------- | :------: | ------------------------------------------------------------ | | auto.setWindowFilter() | UiObject | 设置窗口过滤器。 | | **参数名** | **类型** | | | filter | Function | 参数为窗口([AccessibilityWindowInfo](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo)),返回值为Boolean的函数。 | auto.setWindowFilter(filter) **[v4.1.0新增]** * `filter` {Function} 参数为窗口([AccessibilityWindowInfo](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo)),返回值为Boolean的函数。 设置窗口过滤器。这个过滤器可以决定哪些窗口是目标窗口,并影响选择器的搜索。例如,如果想要选择器在所有窗口(包括状态栏、输入法等)中搜索,只需要使用以下代码: ``` auto.setWindowFilter(function(window){ //不管是如何窗口,都返回true,表示在该窗口中搜索 return true; }); ``` 又例如,当前使用了分屏功能,屏幕上有Auto.js和QQ两个应用,但我们只想选择器对QQ界面进行搜索,则: ``` auto.setWindowFilter(function(window){ // 对于应用窗口,他的title属性就是应用的名称,因此可以通过title属性来判断一个应用 return window.title == "QQ"; }); ``` 选择器默认是在当前活跃的窗口中搜索,不会搜索诸如悬浮窗、状态栏之类的,使用WindowFilter则可以控制搜索的窗口。 需要注意的是, 如果WindowFilter返回的结果均为false,则选择器的搜索结果将为空。 另外setWindowFilter函数也会影响`auto.windowRoots`的结果。 该函数需要Android 5.0以上才有效。 ## 获取过滤的窗口布局元素 | auto.windowRoots | 函数名 | 返回值 | 备注 | | ------------------ | :----: | -------------------------------------------------------- | | auto.windowRoots() | Array | 返回当前被WindowFilter过滤的窗口的布局根元素组成的数组。 | auto.windowRoots **[v4.1.0新增]** * {Array} 返回当前被WindowFilter过滤的窗口的布局根元素组成的数组。 如果系统是Android5.0以下,则始终返回当前活跃的窗口的布局根元素的数组。 # SimpleActionAutomator > Stability: 2 - Stable SimpleActionAutomator提供了一些模拟简单操作的函数,例如点击文字、模拟按键等。这些函数可以直接作为全局函数使用。 ## 点击txt控件 | click(text, i) | 函数名 | 返回值 | 备注 | | ---------- | :------: | ------------------------------------------------------------ | | click() | 布尔型 | 返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 | | **参数名** | **类型** | | | text | 字符串 | 要点击的文本 | | i | 整数型 | 如果相同的文本在屏幕中出现多次,则i表示要点击第几个文本, i从0开始计算 | click(text[, i]) * `text` {string} 要点击的文本 * `i` {number} 如果相同的文本在屏幕中出现多次,则i表示要点击第几个文本, i从0开始计算 返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 该函数可以点击大部分包含文字的按钮。例如微信主界面下方的"微信", "联系人", "发现", "我"的按钮。 通常与while同时使用以便点击按钮直至成功。例如: ``` while(!click("扫一扫")); ``` 当不指定参数i时则会尝试点击屏幕上出现的所有文字text并返回是否全部点击成功。 i是从0开始计算的, 也就是, `click("啦啦啦", 0)`表示点击屏幕上第一个"啦啦啦", `click("啦啦啦", 1)`表示点击屏幕上第二个"啦啦啦"。 > 文本所在区域指的是,从文本处向其父视图寻找,直至发现一个可点击的部件为止。 ## 点击区域控件 |click | 函数名 | 返回值 | 备注 | | ---------- | :------: | ------------------------------------------------------------ | | click() | 布尔型 | 点击在指定区域的控件。当屏幕中并未包含与该区域严格匹配的区域,或者该区域不能点击时返回false,否则返回true。 | | **参数名** | **类型** | | | left | 整数型 | 要点击的长方形区域左边与屏幕左边的像素距离 | | top | 整数型 | 要点击的长方形区域上边与屏幕上边的像素距离 | | bottom | 整数型 | 要点击的长方形区域下边与屏幕下边的像素距离 | | right | 整数型 | 要点击的长方形区域右边与屏幕右边的像素距离 | click(left, top, bottom, right) * `left` {number} 要点击的长方形区域左边与屏幕左边的像素距离 * `top` {number} 要点击的长方形区域上边与屏幕上边的像素距离 * `bottom` {number} 要点击的长方形区域下边与屏幕下边的像素距离 * `right` {number} 要点击的长方形区域右边与屏幕右边的像素距离 **注意,该函数一般只用于录制的脚本中使用,在自己写的代码中使用该函数一般不要使用该函数。** 点击在指定区域的控件。当屏幕中并未包含与该区域严格匹配的区域,或者该区域不能点击时返回false,否则返回true。 有些按钮或者部件是图标而不是文字(例如发送朋友圈的照相机图标以及QQ下方的消息、联系人、动态图标),这时不能通过`click(text, i)`来点击,可以通过描述图标所在的区域来点击。left, bottom, top, right描述的就是点击的区域。 至于要定位点击的区域,可以在悬浮窗使用布局分析工具查看控件的bounds属性。 通过无障碍服务录制脚本会生成该语句。 ## 长按txt控件 | longClick(text, i) | 函数名 | 返回值 | 备注 | | ----------- | :------: | ------------------------------------------------------------ | | longClick() | 布尔型 | 返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 | | **参数名** | **类型** | | | text | 字符串 | 要长按的文本 | | i | 整数型 | 如果相同的文本在屏幕中出现多次,则i表示要长按第几个文本, i从0开始计算 | longClick(text, i) * `text` {string} 要长按的文本 * `i` {number} 如果相同的文本在屏幕中出现多次,则i表示要长按第几个文本, i从0开始计算 返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 当不指定参数i时则会尝试点击屏幕上出现的所有文字text并返回是否全部长按成功。 ## 滑动上滑或左滑控件 | scrollUp(i) | 函数名 | 返回值 | 备注 | | ---------- | :------: | ------------------------------------------------------------ | | scrollUp() | 布尔型 | 找到第i+1个可滑动控件上滑或**左滑**。返回是否操作成功。屏幕上没有可滑动的控件时返回false。 | | **参数名** | **类型** | | | i | 整数型 | 要滑动的控件序号 | scrollUp([i]) * `i` {number} 要滑动的控件序号 找到第i+1个可滑动控件上滑或**左滑**。返回是否操作成功。屏幕上没有可滑动的控件时返回false。 另外不加参数时`scrollUp()`会寻找面积最大的可滑动的控件上滑或左滑,例如微信消息列表等。 参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如`scrollUp(0)`为滑动第一个可滑动控件。 ## 滑动下滑或右滑控件 | scrollDown(i) | 函数名 | 返回值 | 备注 | | ------------ | :------: | ------------------------------------------------------------ | | scrollDown() | 布尔型 | 找到第i+1个可滑动控件下滑或**右滑**。返回是否操作成功。屏幕上没有可滑动的控件时返回false。 | | **参数名** | **类型** | | | i | 整数型 | 要滑动的控件序号 | scrollDown([i]) * `i` {number} 要滑动的控件序号 找到第i+1个可滑动控件下滑或**右滑**。返回是否操作成功。屏幕上没有可滑动的控件时返回false。 另外不加参数时`scrollUp()`会寻找面积最大的可滑动的控件下滑或右滑。 参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如`scrollUp(0)`为滑动第一个可滑动控件。 ## 输入文本(覆盖) | setText(i, text) | 函数名 | 返回值 | 备注 | | ---------- | :------: | --------------------------------------------------- | | setText() | 布尔型 | 返回是否输入成功。当找不到对应的文本框时返回false。 | | **参数名** | **类型** | | | i | 整数型 | 表示要输入的为第i + 1个输入框 | | text | 字符串 | 要输入的文本 | setText([i, ]text) * i {number} 表示要输入的为第i + 1个输入框 * text {string} 要输入的文本 返回是否输入成功。当找不到对应的文本框时返回false。 不加参数i则会把所有输入框的文本都置为text。例如`setText("测试")`。 这里的输入文本的意思是,把输入框的文本置为text,而不是在原来的文本上追加。 ## 输入文本(追加) | input(i, text) | 函数名 | 返回值 | 备注 | | ---------- | :------: | --------------------------------------------------- | | input() | 布尔型 | 返回是否输入成功。当找不到对应的文本框时返回false。 | | **参数名** | **类型** | | | i | 整数型 | 表示要输入的为第i + 1个输入框 | | text | 字符串 | 要输入的文本 | input([i, ]text) * i {number} 表示要输入的为第i + 1个输入框 * text {string} 要输入的文本 返回是否输入成功。当找不到对应的文本框时返回false。 不加参数i则会把所有输入框的文本追加内容text。例如`input("测试")`。