> 文档中心 > 无障碍服务AccessibilityService详解

无障碍服务AccessibilityService详解


无障碍服务

什么是无障碍?为什么需要无障碍?

让应用使用起来没有障碍。Android应用的目标是让所有人都可以使用,包括但不限于视力受损、色盲、听力受损、精细动作失能的人。要想这些有无障碍需求的用户有更好的体验,那么开发应用就要多考虑无障碍功能。

Android无障碍服务

无障碍服务是 Android框架的一项功能,旨在为了给使用Android设备的残障人士提供交互反馈,让他们能够更方便的使用Android设备。

常见无障碍服务示例

  • 开关访问:允许行动不便的 Android 用户使用一个或多个开关与设备进行交互。
  • 语音访问:允许行动不便的 Android 用户使用语音命令控制设备。
  • Talkback:视力受损或盲人用户常用的屏幕阅读器。

如何构建自己的无障碍服务?

1.新建TestAccessibilityService.java类继承AccessibilityService;

import android.accessibilityservice.AccessibilityService;import android.view.accessibility.AccessibilityEvent;/** * @author fenghaitao * @time 2021/8/30 12:08 */public class TestAccessibilityService extends AccessibilityService {    @Override    public void onAccessibilityEvent(AccessibilityEvent event) {    }    @Override    public void onInterrupt() {    }}

2.在/res/xml/目录下新建服务配置文件accessibility_service_config.xml,在里面添加相关的配置信息。

字段说明:

  • description 说明
  • packageNames 要监控的应用包名,多个应用用“,”隔开;
  • accessibilityEventTypes 此服务希望接收的事件类型;
  • accessibilityFlags 辅助功能附加的标志,多个使用 ’ | '分隔,如flagRequestFilterKeyEvents 能够监听到系统的物理按键;
  • accessibilityFeedbackType 反馈类型,有语音、视觉、触觉等;
  • notificationTimeout 同一类型的两个辅助功能事件发送到服务的最短间隔(毫秒,两个辅助功能事件之间的最小周期);
  • canRetrieveWindowContent 辅助功能服务是否能够取回活动窗口内容的属性;
  • settingsActivity 允许用户修改辅助功能的activity组件名称;

也可以运行时在服务的onServiceConnected()方法中动态配置,示例如下:

AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();serviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;  //事件类型serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;//设置回馈给用户的方式serviceInfo.packageNames = pachage;serviceInfo.notificationTimeout = 100;   //setServiceInfo(serviceInfo);

3.在AndroidManifest.xml中进行声明,并引用accessibility_service_config.xml配置文件。

                 

4.将程序安装并打开开关。
打开开关方式有两种:

  • 如果系统中有原生的setting应用,可以直接在无障碍条目中打开。
  • 通过adb命令设置相关属性值打开:

settings put secure accessibility_enabled 1
settings put secure enabled_accessibility_services com.cvte.tv.texttospeech/com.cvte.tv.texttospeech.TTSAccessibilityService(有两个服务时用"|"隔开)

无障碍服务的流程分析

总体流程如下:
在这里插入图片描述

AccessibilityEvent事件是如何产生和发送的?

在这里插入图片描述

  1. view获取焦点或者被选中时,内部会调用相关的方法初始化AccessibilityEvent的相关信息;
  2. 在onPopulateAccessibilityEventInternal()方法中设置AccessibilityEvent文本,在onInitializeAccessibilityNodeInfoInternal()方法中设置AccessibilityNodeInfo的文本;
  3. 调用ViewParent的实现类ViewRootImpl中requestSendAccessibilityEvent()方法;
  4. AccessibilityManager通过IAccessibilityManager跨进程调用AccessibilityManagerService的sendAccessibilityEvent()方法;
  5. 最终通过遍历AccessibilityServiceConnection将事件消息分发到各个AccessibilityService服务中。

AccessibilityService是如何接收AccessibilityEvent事件?

在这里插入图片描述

  1. AccessibilityService是一个抽象类,继承于Service,提供两个抽象方法onAccessibilityEvent() 和 onInterrupt();实现了 onBind() 方法,在其中创建了一个IAccessibilityServiceClientWrapper对象。
  2. 而IAccessibilityServiceClientWrapper继承于IAccessibilityServiceClient.Stub类,可以猜测到,AccessibilityService为一个远程Service,是用跨进程进行通信的。
  3. 当Client端调用onAccessibilityEvent()方法时,通过HandlerCaller处理消息,并调用CallBacks的onAccessibilityEvent()方法,最后在回调中调用 AccessibilityService.this.onAccessibilityEvent(event)。

AccessibilityService是如何与客户端绑定的?

在这里插入图片描述

  1. AccessibilityManagerService初始化时,注册应用监视器和用户状态改变的广播监听,AccessibilityManagerService是一个系统服务,由SystemService启动;
  2. 应用监视器广播是用来监听应用状态的改变;
  3. 以及监听用户切换、用户解锁、用户被移除等状态改变;
  4. 当状态改变时,调用updateServicesLocked()遍历无障碍服务列表,判断是否启用,进行绑定或解绑;
  5. AccessibilityServiceConnection.java>>>bindLocked()>>>>mContext.bindServiceAsUser();

如何通过AccessibilityService远程操作view?

图片来自于:https://blog.csdn.net/u010255127/article/details/79184399
在这里插入图片描述

无障碍服务的应用

  1. TalkBack;
  2. 自动获取短信验证码;
  3. 自动化测试;
  4. 外挂:抢红包、抢单;

无障碍服务防御

  1. 检测 or 禁止相关外挂的辅助模式开启。
    a)通过getInstalledAccessibilityServiceList()方法获取所有的无障碍服务,查看这些服务是否有在监控你的应用;
    b)通过ContentObserver监听enabled_accessibility_services属性值变化,当有服务开启重复a)步骤检测,防止被恶意软件监控;
  2. Event干扰:通过发送无规律的AccessibilityEvent来干扰恶意软件的逻辑判断。
  3. onTouch替换onClick,屏蔽点击事件。
  4. 重写View的findViewsWithText()方法,防止插件通过文本查找到相关的view。