安卓无障碍操作实例讲解

作者:创世魂

 

一、无障碍操作

 

● 帮助说明

 

无障碍的所有操作均位于“无障碍服务支持”模块中,使用时首先需要添加其模块。

 

● 准备工作

 

1、下载“开发者助手”APP

① 可进入酷安网下载:https://www.coolapk.com/apk/com.toshiba_dealin.developerhelper

② 本程序的主要作用:获取APP组件ID值,通过获取的ID值可实现对该组件进行一些操作。

③ 例如:模拟点击、获取组件内容等。

④ 安装完毕后,会在手机上看到下图所示的软件图标。

⑤ 注意:如果手机没有进行root,本软件运行可能会有一些异常情况,但不影响软件节点分析。

 

2、开启“开发者助手”无障碍服务。

① 打开系统“设置”找到“无障碍”,打开无障碍后,找到“开发者助手”点击进入。

② 注:不同系统之间,无障碍的位置可能有所差异,具体查看该手机的帮助手册。

 

③ 进入后点击开关按钮打开该服务。

 

3、打开“开发者助手”APP。

① 打开软件后勾选前三个选项,最后点击黄色箭头所指向的按钮。

② 如果前三个选项已处于勾选状态,则直接点击按钮。

 

③ 点击按钮后“开发者助手”窗口将关闭,桌面上将出现如图所示的悬浮按钮。

 

 

● 查看窗口名

 

1、打开任意APP。

2、点击“开发者助手”悬浮按钮将出现以下界面。

3、窗口名就位于“当前Activity”

 

4、点击窗口名后可弹出信息框,可对窗口名进行复制。

 

 

● 查看组件ID

 

1、点击“开发者助手”悬浮按钮将出现以下界面。

2、点击界面中的“点击开始”按钮,开始分析界面。

 

3、分析完毕后,软件上会出现绿色的方框。

注:方框的数量由软件内的资源量决定。

 

4、此时点击“按钮”后会出现如下图所示的控件属性。

5、“id-Name”一栏后显示的就就是当前组件的ID值。

注意:有些软件的组件可能没有ID值。

注意2:ID值在实际使用时,只要后面的“rg_n”

 

6、点击ID值后会弹出信息框,可进行ID值的复制操作。

 

 

● 创建无障碍服务

 

1、准备工作:

① 打开火山安装目录内“ samples\vprj_android\samples\accessibility\src”目录。

② 复制当前目录内的“res”文件夹。

 

2、粘贴res文件夹:

① 右键项目,选择“打开所在的文件夹”

 

② 把复制的“res”文件夹粘贴到本项目的目录内。

③ 注意:本文件夹内的任何文件名都不要随意修改。

 

3、无障碍描述信息填写:

① 打开当前项目“res\values”目录。

② 使用记事本编辑“vol_accessibility_service_strings.xml”文件。

③ 当前文件中可编辑“无障碍描述”信息,描述信息会显示在“无障碍设置”中。

 

4、定义无障碍服务类:

① 新建一个类(Ctrl+D),基础类填写“无障碍服务类”,名称随意勾选公开。

② 属性名:“@安卓.附加清单”

属性值:“<. android:label="火山自定义无障碍服务">

<meta-data android:name="android.accessibilityservice" android:resource = "@xml/voldev_accessibility_service_config"/> </.>”

③ 属性名:“@安卓.外部资源”

属性值:“res”

本属性的作用,就是用来指定复制过来的“res”文件夹。

注意:本文件夹名称不能修改。

④ 属性名:“@强制输出”

属性值:“真”

火山开发采用按需求编译模式,未被引用的代码都会被剔除。

使用本属性可强制输出,让本服务被正常编译。

 

5、添加虚拟方法:

① 右键“无障碍服务类”

② 选择“添加‘XX’的虚拟方法”

 

③ 依次添加“服务已连接”“被解除所有绑定”方法。

 

④ 添加完毕后,让当前两个虚拟方法分别弹出提示框。

这两个虚拟方法可以理解为“无障碍服务”的开启和关闭的监听事件。

开启后会触发“服务已连接”,关闭后会触发“被解除所有绑定”

 

6、开启程序无障碍:

① 编译安装程序,安装后就可在系统设置无障碍中看到当前程序的无障碍服务。

② 点击进入当前服务。

 

③ 进入后可看到“无障碍服务描述文本”以及“服务开关”,默认处于关闭状态。

 

④ 运行效果如下图(GIF)

当开关开启或关闭,当前程序都会监听到当前服务是否开启或关闭。

 

 

● 判断当前无障碍服务是否开启

 

帮助说明:

1、判断无障碍服务是否开启,需要用到三个类

无障碍管理类:系统级服务,用于对无障碍事件的调度或查询系统当前的无障碍服务状态.

① 本类可单独使用,不会依赖无障碍服务。

② 获取实例方法:“安卓环境.获取系统服务 (本对象, 安卓环境.无障碍管理服务)”

无障碍服务信息列表类:本类是列表模板类,可通过“无障碍管理类.取已启用服务列表()”获取本对象。

③ 本对象中存储了所有的无障碍信息。

无障碍服务信息类:本类中存储了,单个的无障碍信息数据。

④ 可通过“无障碍服务信息列表类.取成员()”获取本对象。

 

2、除了以上三个大类外,还需要用到三个方法

子文本替换:取出的无障碍服务信息中包含多余的字符,需要通过本方法进行字符过滤。

取类名:本方法可用来取出指定类的java名称,可用来记录或者对比,返回值为文本型。

文本包含:通过本方法可判断所有已经开启的无障碍服务中是否包含当前服务。

如果包含了当前服务,则当前服务必然处于开启状态。

 

界面准备如下图:

打开启动类界面设计器,拖放一个“按钮”即可,

 

代码编写(1):

1、新建一个方法(Ctrl+M),方法名随意,返回值填写“逻辑型”

2、定义类型为“无障碍管理类”变量,勾选参考,通过“安卓环境.获取系统服务()”方法获得本对象。

因本方法返回的是“对象类”,因此需要将其强转为“无障碍管理类”,并赋值给定义的变量。

3、定义类型为“无障碍服务信息列表类”变量,勾选参考。

通过“无障碍”变量,调用“取已启用服务列表(无障碍反馈类型.所有反馈)”方法,赋值给定义的“服务列表”变量。

本方法可取出所有已启用的无障碍服务。

4、定义“计次”整数变量,利用“循环”方法取出“服务列表”内所有成员。

5、定义类型为“无障碍服务信息类”变量,勾选参考。

通过“服务列表”变量,调用“取成员()”方法,赋值给定义的“无障碍信息”变量。

本方法可依次取出单个的无障碍信息。

6、定义“服务ID”文本型变量,利用“子文本替换()”方法,替换掉“无障碍信息.服务ID”中多余的字符。

每个无障碍服务都有一个固定的服务ID,通过定义的“无障碍信息”变量可获取此ID。

服务ID中存在一个多余的字符“/”,需通过本方法剔除。

7、定义“当前服务名”文本型变量,通过“取类名()”方法,取出“自定义无障碍服务”的java名称。

将取出的名称,赋值给定义的文本型变量。

8、利用“文本包含()”方法,判断“服务ID”中是否存在“当前服务名”

如果存在则执行“返回(真)”,并执行“跳出循环”,表示当前服务已经开启。

9、最后在“循环”方法外,输入“返回(假)”,表示在已经开启的服务列表内未发现当前服务,即当前服务没有开启。

 

代码编写(2):

1、“按钮1”被点击后,直接判断“无障碍服务是否开启()”方法的返回值。

如果返回真,则提示“无障碍服务已经开启”,返回假则提示“没有开启服务”

2、如果没有开启服务可执行“无障碍管理类.打开设置(本对象)”方法,可直接打开无障碍设置界面。

 

运行效果如下图(GIF):

首次运行无障碍服务必然处于关闭状态。

因此点击“按钮1”后会弹出“没有开启服务”并直接打开“无障碍设置”

开启无障碍服务后,点击“返回”可重新回到当前程序。

此时再次点击“按钮1”会提示“无障碍服务已经开启”

 

● 无障碍节点简述和获取方法

 

1、无障碍针对某个程序的窗口进行操作时,会把这个窗口当成一棵大树。

2、如下图所示:当前“窗口”为根节点,窗口上的所有组件全部都是“子节点”

 

3、查找到的节点,通常存储在“无障碍节点信息类”“无障碍节点信息列表类”中。

4、窗口根节点可通过“取根节点活动窗口 ()”方法获取,返回值为“无障碍节点信息类”

5、组件节点通过“窗口根节点值.指定资源ID查找节点 ()”方法获取。

本方法继承自“无障碍节点信息类”,共有两个参数,支持动态调用。

参数1:动态调用时本参数忽略即可,否则填写欲操作的对象。

参数2:填写“程序包名”+“:id/”+“组件ID值”

返回值为“无障碍节点信息列表类”,可通过“取成员()”方法取出指定节点。

 

● 结合上述的节点知识,实现模拟单击

 

获取窗口信息:

通过“开发者助手”获取指定程序的“包名”“窗口名”“组件ID”

 

“通知_收到新事件”帮助文档:

无障碍所有的操作都是基于虚拟方法,参数返回“无障碍事件类”,可进行具体的无障碍操作。

 

代码编写说明:

1、添加“通知_接收新事件”虚拟方法,定义“是否点击”逻辑变量。

① 本虚拟方法会持续监听,“是否点击”变量用于防止按钮重复点击。

2、在虚拟方法下定义三个变量,类型分别为“无障碍节点信息类”“无障碍节点信息列表类”

① 三个变量全部勾选参考,用于存储窗口和组件节点信息。

3、判断“事件对象.事件类型”是否等于“无障碍事件类型.窗口状态改变”

① 顾名思义,用于判断程序窗口是否被改变。

4、利用“文本相等”命令,判断窗口名称是否等于“事件对象.类名”

① 如果相等,代表当前手机显示的窗口为指定的窗口。

5、通过“取根节点活动窗口()”方法,取出窗口节点赋值给“窗口根节点”变量。

6、判断当前窗口节点是否为空对象,防止获取失败。

7、调用“指定资源ID查找节点()”方法,查找“按钮1”的组件。

① 将查找到的节点赋值给“按钮列表”变量。

② 组件ID书写格式:“包名”+“:id/”+“组件id”

8、判断“按钮列表”是否为空对象,或者成员数是否大于0,防止获取失败。

9、通过“取成员()”方法取出当前“按钮节点”

① 因只是一个组件,参数值直接填写0即可。

10、判断“是否点击”变量是否为假,用于防止重复点击。

11、通过“按钮节点”调用“执行动作()”方法,来模拟点击。

“执行动作”帮助文档:

② 参数1:动态调用时省略即可,否则填写当前对象。

③ 参数2:调用方式“无障碍服务节点动作类型.XXX”

④ 参数3:保留空对象即可。


12、最后需要设置“是否点击=真”

 

代码编写如下图:

 

运行结果如下图(GIF):

左图:无障碍下模拟点击,并且只会点击一次。

右图:正常点击状态。

  

 

● 模拟长按

 

代码编写如下图:

在源代码的基础上,将“执行动作()”方法内的参数修改成“无障碍服务节点动作类型.长按操作”即可。

 

运行效果如下图(GIF):

左图:无障碍模拟长按。

右图:正常长按。

  

 

● 无障碍节点信息类

 

帮助文档如下图:

1、本类中所有的属性和方法和“窗口组件”基础类的用法基本一致。

2、可以理解为窗口组件的另外一种表示形式,此处举例“读组件内容”操作。

注意:本类和“窗口组件”基础类同理,并非所有方法都能正常使用。

例如:在本类中存在一个“内容”写属性,但是本属性并不能给“编辑框”赋值,赋值需要用“执行动作”方法。

 

● 取组件内容

 

通过“开发者助手”取出窗口组件信息:

 

代码编写如下图:

取编辑框的组件内容很简单,在源代码的基础上通过“编辑框节点”调用“内容”读属性即可。

注意:取组件内容仅限于“按钮”“文本框”或者“编辑框”等存储文本字符串的组件。

并不能读取图片框的图片数据。

 

运行结果如下图(GIF):

打开“计算器”这个程序,编辑框的内容就会被弹出。

 

● 写组件内容

 

帮助说明:

写组件内容无法修改图片框组件的,只能修改编辑框类的组件数据。

 

代码编写如下图:

1、定义“数据包类”变量,调用“写文本字段()”方法,设置要写入的新内容。

字段名务必填写:无障碍服务节点动作参数类型.指定文本内容。

2、调用“睡眠当前线程()”延时1秒后调用“执行动作()”方法。

参数1:必须填写“无障碍服务节点动作类型.设置文本”

参数2:填写定义的“数据包”变量。

 

运行效果如下图(GIF):

 

 

● 监听指定编辑框内容改变

 

想要实现监听指定编辑框内容被改变,需要学习两个新的方法。

“查找指定焦点节点”“对象是否相等”

 

“查找指定焦点节点”帮助文档:

1、本方法继承自“无障碍服务类”

2、通过本方法可查找指定焦点节点,参数值填写“假”即可查找编辑框组件。

3、本方法的返回值为“无障碍节点信息类”

 

“对象是否相等”帮助文档:

1、本方法继承自对象类。

2、顾名思义,通过本方法可判断两个对象是否相等。

3、相等返回真,不相等返回假。

 

代码编写如下图:

1、定义一个“逻辑型”的成员变量,用于判断是否为指定窗口。

2、判断“事件类型”是否为“窗口状态改变”,用于确定逻辑变量的逻辑值。

3、判断“事件类型”是否为“文本已改变”,用于监听内容被改变。

4、判断是否为指定窗口,如果为指定窗口则执行编辑框节点判断操作。

5、查找要监听的编辑框节点。

6、调用“查找指定焦点节点()”方法,查找带有焦点的编辑框节点。

7、如果两个节点相等,则表示要监听的编辑框内容被改变。

 

运行效果如下图(GIF):

 

● 监听指定编辑框选区被改变

 

代码编写如下图:

在源代码的基础上简单修改即可实现本功能。

1、判断“事件类型”是否等于“文本选择被改变”

2、继续判断是否为指定窗口。

3、取出要监听的编辑框节点。

4、判断选区位置是否相同,目的是判断是否存在选区。

5、如果存在选区,计算选区长度后,利用“取子文本()”方法取出被选择文本。

 

运行效果如下图(GIF):

可看到选择第一个编辑框内容,会弹出选区文本。

选择第二个编辑框无任何反应。

 

● 监听指定组件被单击

 

代码编写如下图:

在源代码的基础上简单修改即可实现本功能。

1、判断“事件类型”是否等于“被单击”

2、继续判断是否为指定窗口。

3、取出要监听的组件节点。

4、调用“事件对象.取节点信息()”方法,可取出当前响应事件的组件节点。

5、调用“对象是否相等()”方法,判断两个节点对象是否相等。

6、如果相等表示指定组件被点击,不相等则相反。

 

运行效果如下图(GIF):

 

● 监听状态栏消息内容

 

代码编写如下图:

在源代码的基础上简单修改即可实现本功能。

1、判断“事件类型”是否等于“通知栏状态改变”

2、随后判断“事件对象.取分配对象()”是否属于“安卓通知栏”

3、定义类型为“字符串列表类”变量,勾选参考,调用“取文本()”方法赋值给字符串变量。

4、通过字符串变量调用“取成员()”方法,取出的最后一个成员就是当前状态栏显示文本。

① 安卓5.X以下版本,通知栏消息会在状态栏显示消息文本

② 5.X以上不再支持文本显示,但是并不影响消息监听。

③ 监听的状态栏内容,实际上就是监听的通知栏消息。

 

运行效果如下图(GIF):

点击要监听的软件按钮后,当前程序会弹出一条通知消息。

因当前系统是安卓5.1,状态栏内容并不会显示在状态栏上,但并不影响无障碍程序监听。

 

● 模拟通知栏消息点击

 

代码编写如下图:

在源代码的基础上简单修改即可实现本功能。

1、定义类型为“安卓通知栏”的变量,勾选参考。

2、取出分配对象强转为“安卓通知栏”并赋值给“通知栏”变量。

3、通过定义的“通知栏”变量调用“取条目启动对象().发送()”,即可实现模拟通知栏消息点击。

 

运行效果如下图(GIF):

左图:无障碍模拟通知栏点击。

右图:正常状态下点击通知栏消息。