AccessibilityService
AccessibilityService介绍
AccessibilityService可以检测当前界面中UI事件的变化,在开发者的手中,可以利用它实现自动化测试。
google 官方文档 ANDROID_API
创建AccessibilityService
AccessibilityService是系统级的service,我们创建一个Service继承AccessibilityService。
/**
* 这个服务是不需要你在activity里去开启的,属于系统级别辅助服务 需要在设置里去手动开启 和我们平常app里
* 经常使用的service 是有很大不同的 非常特殊
* 你可以在 \sdk\samples\android-23\legacy\ApiDemos 这样的目录下 找到这个工程 这个工程下面有一个accessibility
* 包 里面有关于这个服务的demo 当然他们那个demo 非常复杂,但是信息量很大,有兴趣深入研究的同学可以多看demo
* 我这里只实现最基本的功能 且没有做冗余和异常处理,只包含基础功能,不能作为实际业务上线!
*/
public class MyAccessibilityService extends AccessibilityService {
public MyAccessibilityService() {
}
/**
* AccessibilityService 这个服务可以关联很多属性,这些属性 一般可以通过代码在这个方法里进行设置,
* 我这里偷懒 把这些设置属性的流程用xml 写好 放在manifest里,如果你们要使用的时候需要区分版本号
* 做兼容,在老的版本里是无法通过xml进行引用的 只能在这个方法里手写那些属性 一定要注意.
* 同时你的业务如果很复杂比如需要初始化广播啊之类的工作 都可以在这个方法里写。
*/
@Override
protected void onServiceConnected() {
super.onServiceConnected();
}
/**
* 当你这个服务正常开启的时候,就可以监听事件了,当然监听什么事件,监听到什么程度 都是由给这个服务的属性来决定的,
* 我的那些属性写在xml里了。
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
/**
* 事件是分很多种的,我这里是最简单的那种,只演示核心功能,如果要做成业务上线 这里推荐一个方法可以快速理解这里的type属性。
* 把这个type的int 值取出来 并转成16进制,然后去AccessibilityEvent 源码里find。顺便看注释 ,这样是迅速理解type类型的方法
*/
}
@Override
public void onInterrupt() {
}
}
使用这个Service需要在manifest.xml
中添加权限
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>
在res中创建Service的配置文件。
<!--
这个就是给我们的AccessibilityService 设置属性的,当然你也可以在代码里 的 connnect函数里 手动设置。可以向下兼容。
accessibilityFeedbackType 这个属性如果不设置的话 我们那个onAccessibilityEvent 这个回调函数 根本回调不了 所以这里要注意
packageNames 这个属性 就是捕获什么app的行为的,比如我这里写的包名是packageinstaller 那就肯定只能捕获安装器的 事件了
有的rom 安装器可能不是这个包名 那你就要进行特殊设置了,此外这个属性你如果什么都不写 就意味着 你可以捕获所有手机的动作
如果你要做流氓软件的话 可以packageNames 里面什么都不写。。。甚至可以操作支付宝 给你打钱。。。如果你知道用户密码的话。
当然你如果真这么做了 相信捕获一次用户输入密码的行为 也是很容易的。。细思极恐 我就不往下深入了。。。
description 这个就是对你那个申请服务的时候说明了,可以写的煽情一点 让用户打开这个服务的可能性更高一点。。。
-->
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:notificationTimeout="100"
android:packageNames="com.android.packageinstaller"
android:accessibilityFeedbackType="feedbackSpoken"
android:canRetrieveWindowContent="true"
android:description="@string/hint" />
并且在manifest.xml
中声明这个Service,并设置上面的配置文件。
<!-- label 这个就是在设置界面显示的label 应该比较好理解了-->
<service
android:name=".service.MyAccessibilityService"
android:exported="true"
android:label="Liking"
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/taskbackconfig" />
</service>
这样就创建完成了一个AccessibilityService。
AccessibilityService使用
在onAccessibilityEvent
中去设置
switch (eventType) {
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
//这个地方没什么好说的 你就理解成 找到当前界面 包含有安装 这个关键词的 所有节点就可以了。返回这些节点的list
//注意这里的find 其实是contains的意思,比如你界面上有2个节点,一个节点内容是安装1 一个节点内容是安装2,那这2个节点是都会返回过来的
//除了有根据Text找节点的方法 还有根据Id找节点的方法。考虑到众多手机rom都不一样,这里需要大家多测试一下,有的rom packageInstall
//定制的比较深入,可能和官方rom里差的很远 这里就要做冗余处理,可以告诉大家一个小技巧 你就把这些rom的 安装器打开 然后
//通过ddms里 看view结构的按钮 直接进去看就行了,可以直接看到那个界面属于哪个包名,也可以看到你要捕获的那个按钮的id是什么 很方便!
List<AccessibilityNodeInfo> list = event.getSource().findAccessibilityNodeInfosByText("确定");
if (null != list) {
for (AccessibilityNodeInfo info : list) {
if (info.getText().toString().equals("确定")) {
//找到你的节点以后 就直接点击他就行了
info.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}