一:什么是AccessibilityService

       AccessibilityService是Google为了方便那些身体不便的用户来使用Android设备而提供的一种无障碍服务,该服务可以帮助那些身体不便的用户更加简单的使用和操作Android设备

       AccessibilityService运行在后台,并且能够收到由系统发出的一些事件(AccessibilityEvent,这些事件表示用户界面一系列的状态变化),比如焦点改变,输入内容变化,按钮被点击了等等,该种服务能够请求获取当前活动窗口并查找其中的内容.换言之,界面中产生的任何变化都会产生一个时间,并由系统通知给AccessibilityService.这就像监视器监视着界面的一举一动,一旦界面发生变化,立刻发出警报.

流程图:

       根据以上流程图我们基本上是理清了AccessibilityService的操作流程,主要就是目标APP进程发送消息给系统进程,在系统进程接收到消息后再把消息发送给相关的目标AccessibilityService,主要流程就是这些。

      AccessibilityService是Service的子类,但是它的声明周期是由系统来管理的,那也就是说我们要想启动该服务就不能够像平时那样直接startService()了而是需要在Android设备的辅助功能列表中手动开启该服务,当开启该服务后其生命周期就交由系统来管理和维护了。需要注意的是虽然不需要通过startService()等方式来启动AccessibilityService服务,但是AccessibilityService依然是需要在配置文件AndroidManifest.xml中配置。由于AccessibilityService是抽象类不能直接使用,所以需要先自定义一个类来继承AccessibilityService

二:具体的使用

    1:继承系统AccessibilityService

public class ImjCheckService extends AccessibilityService {

    /**
     * 连接成功
     */
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
    }
    /**
     *当窗口发生的事件是我们配置监听的事件时,会回调此方法.会被调用多次
     */
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // 事件入口处
    }
    /**
     * 当服务要被中断时调用.会被调用多次
     */
    @Override
    public void onInterrupt() {
        super.onInterrupt();
    }

    /**
     * 服务关闭
     * @param intent
     * @return
     */
    @Override
    public boolean onUnbind(Intent intent) {   
        return super.onUnbind(intent);

    }
}

onAccessibilityEvent()方法:表示该服务接收系统传递进来的辅助事件(该事件可能是当前窗口内容发生变化触发的,也可能是当前窗口焦点发生变化触发的,还有可能是系统弹出Notification触发的等等),该方法为事件入口,每当监听的指定应用触发了指定事件的时候都会回调此方法

事件类型:

//事件类型 描述
TYPE_VIEW_CLICKED View被点击
TYPE_VIEW_LONG_CLICKED View被长按
TYPE_VIEW_SELECTED View被选中
TYPE_VIEW_FOCUSED View获得焦点
TYPE_VIEW_TEXT_CHANGED View文本变化
TYPE_WINDOW_STATE_CHANGED 打开了一个PopupWindow,Menu或Dialog
TYPE_NOTIFICATION_STATE_CHANGED Notification变化
TYPE_VIEW_HOVER_ENTER 一个View进入悬停
TYPE_VIEW_HOVER_EXIT 一个View退出悬停
TYPE_TOUCH_EXPLORATION_GESTURE_START 触摸浏览事件开始
TYPE_TOUCH_EXPLORATION_GESTURE_END 触摸浏览事件完成
TYPE_WINDOW_CONTENT_CHANGED 窗口的内容发生变化,或子树根布局发生变化
TYPE_VIEW_SCROLLED View滚动
TYPE_VIEW_TEXT_SELECTION_CHANGED Edittext文字选中发生改变事件
TYPE_ANNOUNCEMENT 应用产生一个通知事件
TYPE_VIEW_ACCESSIBILITY_FOCUSED 获得无障碍焦点事件
TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 无障碍焦点事件清除
TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 在给定的移动粒度下遍历视图文本的事件
TYPE_GESTURE_DETECTION_START 开始手势监测
TYPE_GESTURE_DETECTION_END 结束手势监测
TYPE_TOUCH_INTERACTION_START 触摸屏幕事件开始
TYPE_TOUCH_INTERACTION_END 触摸屏幕事件结束
TYPE_WINDOWS_CHANGED 屏幕上的窗口变化事件,需要API 21+
TYPE_VIEW_CONTEXT_CLICKED View中的上下文点击事件
TYPE_ASSIST_READING_CONTEXT 辅助用户读取当前屏幕事件

2: 在AndroidMainifest中注册

 <service
      android:name=".ImjCheckService"
      android:label="@string/app_name"
      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/imgaccessibility" />
</service>

注意以下几点:

  • 添加label标签

        ImjCheckService添加label标签,标签表示服务的名字,应用安装后会在手机辅助功能的列表中显示,若没定义标签则不显示

  • 添加系统权限

        系统权限android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"是一定要添加的,否则该服务会被系统忽略

  • 添加过滤器

        一定要添加intent为的android:name="android.accessibilityservice.AccessibilityService"过滤器,否则该服务会被系统忽略

  • meta-data配置文件

        meta-data中android:name表示配置的服务名称,值是固定写法不能修改,android:resource表示引用的具体配置文件,本例引用的是imgaccessibility.xml文件【注意:此配置是在4.0版本之后的写法,在低版本中可使用另一种写法,这里就不讲解了】

 看完了manifest配置文件后,我们看一下在res目录下的xml文件夹中的imgaccessibility.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    //用于描述此服务的信息,会显示在系统开启服务的设置界面
    android:description="@string/app_accessibility_description"
    //接收EventTypes的包名,多个包名用,隔开
    android:packageNames="com.tencent.mm,com.tencent.mobileqq"
    //可以接收的事件
    android:accessibilityEventTypes="typeAllMask"
    //字面意思:反馈类型.官方解释真的"很详细".
    android:accessibilityFeedbackType="feedbackAllMask"
    //发送2次事件的时间间隔,超过后事件作废
    android:notificationTimeout="100"
    //设置界面,在系统的启动服务界面会出现一个设置按钮,用来打开这个Activity的;
    android:settingsActivity="com.angcyo.SettingsActivity"
    //官方解释很模糊,暂且就使用缺省值吧
    android:accessibilityFlags="flagDefault"
    //表明此服务是否可以读取窗口中的内容,应该是最重要的属性了.在运行时不可修改;
    android:canRetrieveWindowContent="true"/>

三:uiautomatorviewer工具的使用

 好了,配置完了我们的AccessibilityService服务后,接下来就是要具体实现咋们所谓的自动点击的功能,先看下图片,我们要实现的功能是开发一个自动打开桌面的i闽警这个app,然后进入到主页,但是主页加载的可能是消息页面,也可能已经是i民警这个页面。看这些功能主要就是要实现自动点击,那要怎么点击呢。

   

      onAccessibilityEvent()方法,我们可以在该方法中来模拟用户的操作,要模拟点击操作就要得到对应的按钮,然后执行按钮的点击事件;那怎么样才能得到目标按钮这个对象呢?在AccessibilityService中提供了一个getRootInActiveWindow()方法,该方法返回一个代表当前活动窗口的根节点AccessibilityNodeInfo实例对象,该对象保存了当前窗口界面的相关信息,比如控件在窗口的位置信息,id信息,文本信息,类型信息,文本信息等等,它和ViewGroup类似,对外提供了诸如

findAccessibilityNodeInfosByViewId(),findAccessibilityNodeInfosByText(),performAction()等方法。其中findAccessibilityNodeInfosByViewId()是4.3版本之后的新增方法,表示根据给定控件的ID来获取到对应控件,获取到对应控件后就可以通过performAction()方法来执行点击事件了,那怎么获取到指定控件的ID呢?

        在Android的sdk目录中有个tools目录,在该目录下有个uiautomatorviewer工具,该工具很有用,特别是分析apk的页面布局信息,它可以获取到当前手机屏幕上的界面信息,路径如下:

 

       点击中间两项进行截屏,发现有的手机会报上面的错误,有的手机能正常截取到屏幕,如果不能正常截取,我们可以用cmd命令来获取,但是为了不要繁琐的进行命令敲入,我们把截图命令设置成bat文件,就是把txt文档后缀改成bat,直接在点击bat文件就可以截图了:

adb shell uiautomator dump /sdcard/app.uix


adb pull /sdcard/app.uix E:/app.uix

#存到E盘的app.uix文件夹中,在E盘提前建一个app.uix格式的文件夹



adb shell screencap -p /sdcard/app.png


adb pull /sdcard/app.png E:/app.png


#存到E盘的app.png文件夹中,在E盘提前建一个app.png格式的文件夹

 截图后uiautomatorviewer工具点开第一个按钮,引入截图的png和对应的uix文件,点击ok把界面加载进uiautomatorviewer工具

 点击界面上的控件,在右侧可见到对应的控件信息,可看的到界面布局

 

 

 接下来具体的代码咋们工程里看。

参考的文章:

AccessibilityService,打造自己的APP小外挂(上)https://blog.csdn.net/llew2011/article/details/52822148

AccessibilityService源码分析

https://blog.csdn.net/llew2011/article/details/52843637

自动抢红包 https://blog.csdn.net/tinson12321/article/details/89150921

 辅助服务监听系统按键(AccessibilityService最简实例)

https://blog.csdn.net/twk121109281/article/details/100766558

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐