AccessibilityService的使用
一:什么是AccessibilityServiceAccessibilityService是Google为了方便那些身体不便的用户来使用Android设备而提供的一种无障碍服务,该服务可以帮助那些身体不便的用户更加简单的使用和操作Android设备,这些操作包括文字转语音,触觉反馈,收拾操作,轨迹球和手柄操作等。AccessibilityService提供的这种服务就是用来监听指定的应用的,例如监
一:什么是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
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)