引言
提起AccessibilityService首先想到的肯定是抢红包插件。没错,目前基本上抢红包插件分为两类:root和免root,而免root的红包插件全是基于AccessibilityService。随着AccessibilityService的广泛应用,现今已经有比较多的方法可以防御基于AccessibilityService实现的自动化插件了。有兴趣的朋友可以参考这篇文章:红包外挂史及AccessibilityService分析与防御。
本文通过AccessibilityService加上OpenCV辅助识别一些关键的特征,以此在高版本微信中实现抢红包的效果。
AccessibilityService基本用法
1、继承AccessibilityService
编写自己的Service类,必须重写onAccessibilityEvent()方法和onInterrupt()方法
public class HongbaoService extends AccessibilityService {
/**
* 当启动服务的时候就会被调用(非必须重写)
*/
@Override
protected void onServiceConnected() {
super.onServiceConnected();
}
/**
* 监听窗口变化的回调
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
//根据事件回调类型进行处理
}
/**
* 中断服务的回调
*/
@Override
public void onInterrupt() {
}
}
下面简要地介绍用到的几个AccessibilityEvent的事件类型
事件类型 | 描述 |
---|---|
TYPE_VIEW_CLICKED | View被点击 |
TYPE_VIEW_LONG_CLICKED | View被长按 |
TYPE_VIEW_SELECTED | View被选中 |
TYPE_NOTIFICATION_STATE_CHANGED | 状态栏发生变化 |
TYPE_WINDOW_CONTENT_CHANGED | 窗口内容发生变化 |
TYPE_WINDOW_STATE_CHANGED | 打开弹出窗口、菜单、对话框等的时候触发 |
2、声明服务
首先,我们需要在manifests中配置该服务信息
<service
android:name=".service.HongbaoService"
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/accessible_service_config" />
</service>
我们必须注意:任何一个信息配置错误,都会使该服务无反应
- android:label:在无障碍列表中显示该服务的名字(默认与APP名字相同)
- android:permission:需要指定BIND_ACCESSIBILITY_SERVICE权限,这是4.0以上的系统要求的
- intent-filter:这个name是固定不变的
##3、配置服务参数
配置服务参数是指:配置用来接受指定类型的事件,监听指定package,检索窗口内容,获取事件类型的时间等等。其配置服务参数有两种方法: - 方法一:安卓4.0之后可以通过meta-data标签指定xml文件进行配置
- 方法二:通过代码动态配置参数
这里我使用的是第一种方法:
在项目中增加accessible_service_config文件,配置如下:
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_description"
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged|typeNotificationStateChanged"
android:accessibilityFeedbackType="feedbackAllMask"
android:packageNames="com.tencent.mm"
android:notificationTimeout="300"
android:settingsActivity="com.shareder.ln_jan.wechatluckymoneygetter.activities.MainActivity"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:canPerformGestures="true"/>
- accessibilityEventTypes:表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如窗口打开,滑动,焦点变化,长按等。具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知
- accessibilityFeedbackType:表示反馈方式,比如是语音播放,还是震动
- canRetrieveWindowContent:表示该服务能否访问活动窗口中的内容。也就是如果你希望在服务中获取窗体内容,则需要设置其值为true
- description:对该无障碍功能的描述
- notificationTimeout:接受事件的时间间隔,这里我设置的是300
- packageNames:表示对该服务是用来监听哪个包的产生的事件,如"com.tencent.mm"为微信的包名
- canPerformGestures: 安卓7.0后可通过dispatchGesture实现点击屏幕的操作,如需用此方法需将canPerformGestures设置为true
4、预备知识
4.1、获取节点信息
获取了界面窗口变化后,这个时候就要获取控件的节点。整个窗口的节点本质是个树结构,通过以下操作节点信息
1、获取窗口节点(根节点)
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
2、获取指定子节点(控件节点)
//通过文本找到对应的节点集合
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(text);
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(clickId);
4.2、模拟点击的方法
获取节点信息后可通过performAction方法或dispatchGesture方法产生点击屏幕的效果
1、performAction
//模拟点击
accessibil