Android小技巧之AccessibilityService(无障碍)

2,893 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第二十五天,[点击查看活动详情](juejin.cn/post/712312…

Android小技巧之AccessibilityService(无障碍)

前言

本文章收录Android小技巧系列,该系列是在日常工作用不上但是该功能可以实现一些比较好玩的app。该文章的主角是AccessibilityService(无障碍),该功能可以实现模拟用户操作手机,有这个这个就可以实现一些,重复度较高的操作,比如:办公软件的打卡,抢红包,自动回复等相关操作。

AccessibilityService

AccessibilityService是Android提供的开发人员实现无障碍模式的一个服务类,如果我们要实现无障碍的功能,我们就要继承与AccessibilityService类,但是光继承还是远远不够的,那么我们就来看看,使用一个AccessibilityService需要那些步骤:

继承 AccessibilityService

我们声明一个类继承与AccessibilityService

class AccessibilityDemoService : AccessibilityService(){

    //无障碍服务链接的时候回调
    override fun onServiceConnected() {
        super.onServiceConnected()
        ToastUtils.showLong("onServiceConnected")
    }

    //无障碍服务监听事件回调
    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
         ToastUtils.showLong("onAccessibilityEvent")
    }

    //无障碍服务断开的时候回调
    override fun onInterrupt() {
        ToastUtils.showLong("onInterrupt")
    }
}

解析:

当我们继承AccessibilityService的时候onAccessibilityEventonInterrupt是必须重写,onServiceConnected也很重要,我们重写一些,可以进行一些初始化的操作,细心的你会发现我们在每个回调显示了Toast,每个回调都是在主线程所以Toast不会报错,也就是不能做耗时操作,要不然会出先ARN

在AccessibilityService里只能加Log或者加Toast来看数据,加了断点也不停

AndroidManifest.xml配置

我们创建了AccessibilityDemoService还需要在清单文件里,声明一下:

<service
    //在无障碍设置显示的名字
    android:label="@string/app_name"
    //自己声明的类
    android:name=".AccessibilityDemoService"
    //支持其它应用调用当前组件
    android:exported="true"
    //需要指定BIND_ACCESSIBILITY_SERVICE权限,这是4.0以上的系统要求的
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    //运行的进程
    android:process=":BackgroundService">
    //必须声明这个为无障碍服务,声明了才设置里显示
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <!--       通过xml文件完成辅助功能相关配置,也可以在onServiceConnected中动态配置-->
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_config" />

</service>

解析:

和普通的Service配置有点区别,我们也了解这个配置的作用,最后两个配置是一定要配置的,要不然就启动不起无障碍服务,我们还发现最后要配置一个 android:resourcexml文件,这个配置也可以在之前说的onServiceConnected方法中设置,提供两种配置,一个静态,一个动态,我们先看一下静态的配置。

配置文件

  1. 配置文件配置

我们直接看accessibility_config.xml的内容:

 <accessibility-service
     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
     android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp"
     android:accessibilityFeedbackType="feedbackSpoken"
     android:notificationTimeout="100"
     android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity"
     android:canRetrieveWindowContent="true"
/>

解析:

上面只写了一部分的属性,全部属性和属性详情如下表:

属性介绍
android:accessibilityEventTypes此服务希望接收的事件类型,如 AccessibilityEvent.
android:accessibilityFeedbackType此服务提供的反馈类型在 中指定 AccessibilityServiceInfo
android:accessibilityFlags中指定的附加标志 AccessibilityServiceInfo
android:canRequestEnhancedWebAccessibility属性可访问性服务是否希望能够请求增强的 Web 可访问性增强
android:canRequestFilterKeyEvents属性无障碍服务是否希望能够请求过滤关键事件
android:canRequestTouchExplorationMode属性无障碍服务是否希望能够请求触摸探索模式,在该模式中,大声说出触摸的项目并且可以通过手势探索 UI
android:canRetrieveWindowContent属性无障碍服务是否希望能够检索活动窗口内容
android:canTakeScreenshot属性无障碍服务是否希望能够截屏
android:description无障碍服务使用、可用性或限制的描述
android:interactiveUiTimeout建议的超时时间(以毫秒为单位),用于 为交互式控件返回合适的值。 android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)
android:intro无障碍服务目的或行为的详细介绍。
android:nonInteractiveUiTimeout建议的超时时间(以毫秒为单位),用于 为不包含交互式控件的 UI 返回合适的值。 android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)
android:notificationTimeout两个相同类型的可访问性事件之间的最小时间间隔(以毫秒为单位)被发送到此服务
android:packageNames逗号分隔的包名称,该服务希望从中接收事件(省略所有包
android:settingsActivity允许用户修改此服务设置的活动的完全限定类名。
android:summary无障碍服务目的或行为的简要总结。
android:tileService的完全限定类名TileService与此可访问性服务相关联,以进行一对一映射
  1. 代码配置
override fun onServiceConnected() {
     val serviceInfo = AccessibilityServiceInfo().apply {
         eventTypes = AccessibilityEvent.TYPES_ALL_MASK
         feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASK
         packageNames = arrayOf("com.eg.android.AlipayGphone")//支付宝包名,可以多个
         notificationTimeout = 10
     }
     setServiceInfo(serviceInfo)
    }

我们需要在onServiceConnected方法中设置,上面代码只设置了部分

运行

上面的步骤我们就完成了无障碍的基本流程,但是现在你运行app还不会运行,因为我们需要在设置里开启app的无障碍,我们使用代码跳转:

try {
     startActivity(  Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
 }
 catch (e: Exception){
     startActivity(  Intent(Settings.ACTION_SETTINGS));
 }

然后我们在选我们的应用打开,就会跳转到无障碍设置界面,我们开启我们的应用就可以,你就会看到我们的Toast,效果图吐下:

LPDS_GIF_20220825_160626.gif

常用的操作

我们启动了无障碍,那么我们就可以做一下模拟用户操作,所有操作我们在onAccessibilityEvent方法中进行操作:

  • 锁屏
 override fun onAccessibilityEvent(event: AccessibilityEvent?) {
      event ?: return
      performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN)
  }
  • 打开通知栏
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
    event ?: return
    performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS)
}

我们就简单介绍两个的代码展示,更多请看performGlobalAction的使用

总结

到这里我们就简单的使用一下Android的无障碍功能,无障碍功能可以做很多功能,下一篇我们来实战,使用无障碍来实现企业微信的打开功能。