一、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参数说明见官方文档:
AccessibilityEvent
| 字段名 | 字段说明 | 
|---|---|
| TYPE_NOTIFICATION_STATE_CHANGED | 通知栏状态变化 | 
| TYPE_VIEW_CLICKED | 视图被点击 | 
| TYPE_WINDOW_CONTENT_CHANGED | 窗口内容变化 | 
| TYPE_WINDOW_STATE_CHANGED | 窗口状态变化,即切换activity | 
2. 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>
3. 在资源文件夹新增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