无障碍服务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,在里面添加相关的配置信息。

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:packageNames="com.example.android.apis"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>

字段说明:

  • 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配置文件。

<service
    android:name=".TestAccessibilityService1" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
    </service>

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。
  • 2
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值