
1.android 辅助服务
参考:https://blog.csdn.net/abc6368765/article/details/148281328
介绍
什么是无障碍服务
Android 的无障碍辅助功能(Accessibility)是一套专为残障用户或特殊场景设计的核心技术框架,旨在让所有用户都能便捷地操作设备。其功能覆盖视觉、听觉、运动能力和认知障碍支持,同时为开发者提供标准化 API 以实现应用适配。
在 Android 测试中,无障碍服务不仅可以用于辅助功能开发,还可以用于自动化测试、界面分析和监控。通过无障碍服务,开发者可以模拟用户操作、获取界面信息,甚至实现跨应用的自动化测试。
无障碍服务在 Android 测试中的重要性
无需修改被测应用代码:无障碍服务可以直接监控和操作界面,无需对被测应用进行任何修改。所以无障碍服务非常适合做黑盒测试。
支持跨应用操作:无障碍服务可以监控和操作多个应用的界面,适合测试跨应用场景(如从 A 应用跳转到 B 应用)。
强大的界面分析能力:通过 AccessibilityNodeInfo,可以获取界面的层级结构和控件属性,便于分析和验证界面布局。
自动化测试的灵活性:结合无障碍服务,可以编写灵活的自动化测试脚本,模拟用户操作并验证应用行为。
兼容性强:无障碍服务基于 Android 系统框架,兼容大多数 Android 设备和版本。
目前,一些主流的 Android 自动化框架,或多或少都使用到了无障碍服务的功能。比如 Google 官方提供的 Android 测试框架 UI Automator 就是基于无障碍服务实现的。再比如,Google 官方提供的 Android 白盒测试框架,主要依赖于视图层级(View Hierarchy),但在某些场景下会使用无障碍服务来增强功能。
简单案例
下面我们将会编写一个简单的案例,具体认识一下 Android 无障碍服务 (AccessibilityService) 。此案例主要用于获取当前屏幕上的所有文本信息。
public class ClickAccessibilityService extends AccessibilityService {
private static final String TAG = BASE_TAG + ".ClickAccessibilityService";
private static ClickAccessibilityService mService = null;
public static boolean isConnected() {
return mService != null;
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.i(TAG, "onServiceConnected");
mService = this;
}
@Override
public void onInterrupt() {
Log.i(TAG, "onInterrupt");
mService = null;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
mService = null;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent
accessibilityEvent) {
// 打印无障碍服务的事件类型
int eventType = accessibilityEvent.getEventType();
Log.i(TAG, "onAccessibilityEvent: " + accessibilityEvent.getText());
Log.i(TAG, "onAccessibilityEvent: " + eventType);
}
}
步骤 2:创建无障碍服务配置文件(res/xml/accessibility_service_config.xml)
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"
android:description="@string/app_name"
android:notificationTimeout="100"
android:packageNames="com.android.systemui" />
上述配置定义了服务的行为和功能,确保服务能够接收特定类型的事件、提供反馈、检索窗口内容等。
android:accessibilityEventTypes :指定无障碍服务需要接收的事件类型。typeAllMask表示接收所有类型的无障碍事件(例如点击、焦点变化、文本变化等)。其他可选值:
typeViewClicked:视图点击事件。
typeViewFocused:视图焦点变化事件。
typeWindowContentChanged:窗口内容变化事件。
其他事件可以参考 API 文档。
android:accessibilityFeedbackType: 指定无障碍服务的反馈类型。feedbackGeneric表示提供通用的反馈(例如语音、震动等)。其他可选值:
feedbackSpoken:语音反馈。
feedbackHaptic:震动反馈。
feedbackAudible:声音反馈。
其他事件可以参考 API 文档。
android:accessibilityFlags: 设置无障碍服务的标志位,用于控制服务的行为。flagDefault表示使用默认标志。其他可选值:
flagRequestTouchExplorationMode:请求触摸探索模式。
flagRequestFilterKeyEvents:请求过滤按键事件。
flagReportViewIds:报告视图的 ID。
android:canPerformGestures: 指定无障碍服务是否能够执行手势操作。true表示服务可以执行手势(例如滑动、点击等)。
android:canRetrieveWindowContent: 指定无障碍服务是否能够检索窗口内容。true表示服务可以获取窗口中的内容(例如文本、视图层次结构等)。
android:description:为无障碍服务提供描述信息,通常显示在系统的无障碍设置界面中。
android:notificationTimeout:设置无障碍事件的通知超时时间(以毫秒为单位)。100表示事件通知的超时时间为 100 毫秒。
android:packageNames:指定无障碍服务只监听特定应用程序包的事件。com.android.systemui表示服务只监听系统 UI 的事件。可以指定多个包名,用逗号分隔。
步骤 3:添加无障碍服务声明(AndroidManifest.xml )
<service
android:name=".ClickAccessibilityService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:label="@string/accessibility_tip">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_config" />
</service>
配置信息介绍
在 AndroidManifest.xml 中,无障碍服务(accessibility service)的声明方式与其他服务类似,但它必须完成以下两件事:
指定它处理 “android.accessibilityservice.AccessibilityService” 这个 Intent。
请求 Manifest.permission.BIND_ACCESSIBILITY_SERVICE 权限,以确保只有系统能够绑定到该服务。
如果缺少其中任何一项,系统将忽略该无障碍服务。
配置无障碍服务只接受特定类型事件
无障碍服务可以根据需求灵活配置,例如只接收特定类型的事件、监听指定的应用、限制事件频率、获取窗口内容,或者设置自定义配置界面等。配置无障碍服务有两种方式:
1、第一种方式是在清单文件中声明服务时,通过添加元数据(meta-data)进行配置。步骤 2 配置方式使用的就是这种配置。
2、另一种配置方式是通过代码动态配置无障碍服务。开发者可以在服务运行时,使用AccessibilityServiceInfo类来设置服务的具体行为,例如事件类型、反馈类型、通知超时等。这种方式更加灵活,允许根据应用的实际需求动态调整配置。
启用无障碍服务ClickAccessibilityService
需要在系统设置中启用应用的无障碍服务ClickAccessibilityService

运行效果
开启ClickAccessibilityService无障碍服务
当我们在设置页面开启无障碍服务的一瞬间,会有如下日志打印:
ActivityManager system_server I Start proc 5304:com.example.empty/u0a152 for service {com.example.empty/com.example.empty.ClickAccessibilityService}
EmptyApp.C…ityService com.example.empty I onServiceConnected
1
2
获取SystemUI页面事件
当我们下划划出下拉栏之后。
2025-06-18 20:33:52.139 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.139 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:52.143 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.143 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:52.157 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: [通知栏。, 互联网, T-Mobile,3G, 蓝牙, 已开启, 手电筒, 相机正在使用中, 勿扰, 已关闭, 没有通知, 12:33, 6月18日周三, T-Mobile, 3G, 100%]
2025-06-18 20:33:52.157 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 32
2025-06-18 20:33:52.305 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.305 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:52.328 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.328 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 4096
2025-06-18 20:33:52.365 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.365 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:52.366 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: [通知栏。, 互联网, T-Mobile,3G, 蓝牙, 已开启, 手电筒, 相机正在使用中, 勿扰, 已关闭, 没有通知, 12:33, 6月18日周三, T-Mobile, 3G, 100%]
2025-06-18 20:33:52.366 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 32
2025-06-18 20:33:52.684 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.684 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:52.800 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.800 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:52.922 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:52.922 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:53.051 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:53.051 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
2025-06-18 20:33:53.153 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: []
2025-06-18 20:33:53.153 5304-5304 EmptyApp.C...ityService com.example.empty D onAccessibilityEvent: 2048
模拟点击
修改代码,模拟打开蓝牙
public class ClickAccessibilityService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) { // 打印无障碍服务的事件类型 int eventType = accessibilityEvent.getEventType(); Log.i(TAG, “onAccessibilityEvent: ” + accessibilityEvent.getText()); Log.i(TAG, “onAccessibilityEvent: ” + eventType); if (accessibilityEvent.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { Log.i(TAG, “Windows state has been changed.”); AccessibilityNodeInfo rootNode = getRootInActiveWindow(); if (rootNode == null) { Log.i(TAG, “Root node is null.”); return; } List对ClickAccessibilityService服务进行上述修改,然后重新安装应用,并在设置页面开启无障碍服务。
运行效果
当我们再次下划划出下拉栏之后。
