一、AccessibilityService

根据官方的介绍,是指开发者通过增加类似contentDescription的属性,从而在不修改代码的情况下,让残障人士能够获得使用体验的优化,大家可以打开AccessibilityService来试一下,点击区域,可以有语音或者触摸的提示,帮助残障人士更好的使用App

官方文档:https://developer.android.com/guide/topics/ui/accessibility/service

二、AccessibilityService 开发流程

  1. 确定执行脚本的APK安装包
  2. 通过UIAutomator 获取包名及UI控件ID,或者下载一个开发者助手apk,也可以进行控件ID获取,代码君已经帮你下载好了,需要自取
    http://share.dmjzy.cn/f/17143538-501591536-a374b2(访问密码:8401)
  3. 编写脚本代码
  4. 调试、兼容性处理

三、核心代码

  1. AccessibilityService主要是实现onAccessibilityEvent
public class AccessibilitySampleService extends AccessibilityService{

    /**当无障碍服务连接之后回调*/
   @Override
   public void  onServiceConnected() {
        super.onServiceConnected()
    }

    /**当触发了需要监听的无障碍事件后回调*/
   @Override 
   public void onAccessibilityEvent(AccessibilityEvent event){
       // 获取包名
       String pkgName = event.getPackageName().toString();
       int eventType = event.getEventType();
 
       AccessibilityOperator.getInstance().updateEvent(this, event);
       //过滤出目标包,如果要检测所有包,可以去掉此判断
       if (pkgName.equals(pageName)) {
           AccessibilityLog.printLog("eventType: " + eventType + " pkgName: " + pkgName);
 
           switch (eventType) {
               case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                   //执行具体的脚本
                   toOperator();
                   break;
               case AccessibilityEvent.TYPE_VIEW_CLICKED:
                   break;
               case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
                   break;
               case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                   break;
           }
       }
   } 
   /**无障碍服务断开后回调*/
   @Override 
   public void onInterrupt(){
       // TODO Auto-generated method stub 
   }
}
方法说明
1. onServiceConnected

当声明的无障碍服务连接之后, 系统会回调此方法.
在这个方法里, 可以做一些初始化工作. 比如保存服务的实例 标识服务连接的状态等.

也可以通过android.accessibilityservice.AccessibilityService#getServiceInfo动态更改xml配置文件中声明的无障碍配置信息.

2. onAccessibilityEvent

当监听的事件触发时, 系统会回调此方法, 比如view被点击了 window内容改变了等.

可以用android.view.accessibility.AccessibilityRecord#getSource获取对象AccessibilityNodeInfo, 这个对象就是无障碍操作的核心对象, 通常可以理解为android开发中的view控件.

可以通过AccessibilityNodeInfo对象, 进行控件的点击操作 输入文本操作 滚动操作 获取文本操作等

3. onInterrupt

当中途关闭了无障碍服务时回调, 通常这个时候无障碍服务不可用, 调用api都会失败.

4. AccessibilityService 其他方法说明

方法名

方法说明

disableSelf()

禁用当前服务,也就是在服务可以通过该方法停止运行

findFoucs(int falg)

查找拥有特定焦点类型的控件

getRootInActiveWindow()

如果配置能够获取窗口内容,则会返回当前活动窗口的根结点

performGlobalAction(int action)

执行全局操作,比如返回,回到主页,打开最近等操作,此方法可以模拟用户点击返回键和home键,操作见下面的官方文档

setServiceInfo(AccessibilityServiceInfo info)

设置当前服务的配置信息

getSystemService(String name)

获取系统服务

onKeyEvent(KeyEvent event)

如果允许服务监听按键操作,该方法是按键事件的回调,需要注意,这个过程发生了系统处理按键事件之前

更多AccessibilityService参数说明见官方文档:
https://developer.android.google.cn/reference/kotlin/android/accessibilityservice/AccessibilityService

AccessibilityEvent

字段名

字段说明

TYPE_NOTIFICATION_STATE_CHANGED

通知栏状态变化

TYPE_VIEW_CLICKED

视图被点击

TYPE_WINDOW_CONTENT_CHANGED

窗口内容变化

TYPE_WINDOW_STATE_CHANGED

窗口状态变化,即切换activity

  1. AndroidManifest.xml注册服务
<!-- 注册辅助功能服务-->
       <service
           android:name=".AccessibilitySampleService"
           android:exported="true"
           android:label="码君助手"
           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>
  1. 在资源文件夹新增xml文件夹,新建accessibility_config文件,代码如下
<?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:canRetrieveWindowContent="true"
    android:canPerformGestures="true"
    android:description="@string/accessibility_desc"
    android:notificationTimeout="10" />

<!--  canPerformGestures  //申请手势权限-->
<!--accessibility_desc:码君助手,让你的手机更智能一点 -->
accessibility_config说明

官方文档说明:https://developer.android.google.cn/reference/android/R.styleable#AccessibilityService
这里列举一些比较常用的

字段名

字段说明

accessibilityEventTypes

表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如窗口打开,滑动,焦点变化,长按等.具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知

accessibilityFeedbackType

表示反馈方式,比如是语音播放,还是震动。feedbackGeneric代表所有

canRetrieveWindowContent

表示该服务能否访问活动窗口中的内容.也就是如果你希望在服务中获取窗体内容的化,则需要设置其值为true

notificationTimeout

接受事件的时间间隔,通常将其设置为100即可

packageNames

表示对该服务是用来监听哪个包的产生的事件。如果不写代表监听所有的应用。中间可以用";"来分割。

canPerformGestures

表示可以执行手势属性

canTakeScreenshot

是否能够截屏

4、编写执行脚本

try {
           Thread.sleep(2000);
           AccessibilityOperator.getInstance().clickById("com.xxxx.packagename:id/btn_later");// 关闭弹框
 
           Thread.sleep(1000);
           AccessibilityOperator.getInstance().clickById("com.xxxx.packagename:id/tab_work");//切换到工作tab
           AccessibilityLog.printLog("切换到工作tab: ");
 
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
AccessibilityNodeInfo

方法名

方法说明

findAccessibilityNodeInfosByText()

通过字符串查找节点元素

findAccessibilityNodeInfosByViewId()

通过视图id查找节点元素

performAction()

在节点上执行一个动作,比如点击、向上滑动等,更多操作见下面的官方文档

getParent()

获取父节点

getChild()

获取子节点

isEnabled()

判断节点是否激活

isClickable()

判断节点是否可以点击

isScrollable()

判断节点是否可以滚动

isSelected()

判断节点是否选中

isPassword()

判断节点是否是密码输入框

isFocusable()

判断节点是否可以获取焦点

getText()

获取节点的文本信息

getContentDescription()

节点的内容描述

getViewIdResourceName()

获取节点控件的id ,获取到的值大概是这样的:com.ss.android.ugc.aweme:id/afy

getBoundsInScreen()

获取节点在屏幕中的位置

getClassName()

获取节点的类型/类名,值:android.widget.LinearLayout

getChild()

获取子节点的AccessibilityNodeInfo信息

更多请查看官方文档:
https://developer.android.google.cn/reference/android/view/accessibility/AccessibilityNodeInfo