最近了解了一下这方面的知识,参考网上的一些博客,自己再完善了一下,写了一个自动抢红包的app.
本应用支持QQ和微信挂后台时自动抢红包
支持在微信和QQ的消息列表页面自动抢红包
支持在QQ群和单个好友消息会话页面自动抢红包
不支持在单个微信聊天页面自动抢
其实主要是
AccessibilityService相关的一些知识,可以参考android 文档,以下是国内的链接.
具体代码如下:
一.服务的声明和权限
1.服务与权限的声明
首先需要在
AndroidManifest.xml 里面声明一下AccessibilityService,并指定对应的服务配置文为
accessibilityservice.xml.这一部分的配置可以直接在android的文档上面拷贝就可以,再根据需要调整
<service android:name=".RobMonkeyAccessibilityService" 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/accessibilityservice" /></service>
由于实际功能中涉及到熄屏时自动亮屏并解锁手机,所以还要添加几个权限:
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/><uses-permission android:name="android.permission.WAKE_LOCK" />
2.服务的配置
accessibilityservice.xml
这里定义了需要几个主要项:
a.监听的状态:
android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged"
通知的改变(可以理解为有新通知来了没有);窗口的改变(主要是activity变了没有);窗口内容是否有变(主要是微信里面有用到fargement,所以只是内容变了,Activity没有变)
b.监听的应用
android:packageNames="com.tencent.mm,com.tencent.mobileqq"
<?xml version="1.0" encoding="utf-8"?><accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:notificationTimeout="100" android:packageNames="com.tencent.mm,com.tencent.mobileqq" />
二.AccessibilityService 的继承实现
主要是AccessibilityService的一些使用,其中还有涉及到亮屏和解锁相关的一些东西.
package com.doov.robmoney;import android.accessibilityservice.AccessibilityService;import android.annotation.SuppressLint;import android.app.KeyguardManager;import android.app.Notification;import android.app.PendingIntent;import android.content.Context;import android.os.PowerManager;import android.util.Log;import android.view.accessibility.AccessibilityEvent;import android.view.accessibility.AccessibilityNodeInfo;import java.util.List;public class RobMonkeyAccessibilityService extends AccessibilityService {private static final String TAG = "RobMonkeyAccessibilityService";/*** 是否可以点击红包*/private boolean canGetMonkey = false;private boolean isGetMonkey = false;/*当前窗口状态*/private int mWindowStatus = WINDOW_NONE;/*各种窗口状态*/private final static int WINDOW_LANUCHRE = 1;private final static int WINDOW_RECEIVERUI = 2;private final static int WINDOW_DETAILUI = 3;private final static int WINDOW_OTHER = 4;private final static int WINDOW_NONE = 5;private final static int WINDOW_QQ_LANUCHRE = 6;private PowerManager mPowerManager;private KeyguardManager mKeyguardManager;private KeyguardManager.KeyguardLock mKeyguardLock;private PowerManager.WakeLock mWakeLock;private boolean canGetQQMonkey = true;private AccessibilityNodeInfo mLastMonkeyNode = null;package com.doov.robmoney;import android.accessibilityservice.AccessibilityService;import android.annotation.SuppressLint;import android.app.KeyguardManager;import android.app.Notification;import android.app.PendingIntent;import android.content.Context;import android.os.PowerManager;import android.util.Log;import android.view.accessibility.AccessibilityEvent;import android.view.accessibility.AccessibilityNodeInfo;import java.util.List;public class RobMonkeyAccessibilityService extends AccessibilityService {private static final String TAG = "RobMonkeyAccessibilityService";/*** 是否可以点击红包*/private boolean canGetMonkey = false;private boolean isGetMonkey = false;/*当前窗口状态*/private int mWindowStatus = WINDOW_NONE;/*各种窗口状态*/private final static int WINDOW_LANUCHRE = 1;private final static int WINDOW_RECEIVERUI = 2;private final static int WINDOW_DETAILUI = 3;private final static int WINDOW_OTHER = 4;private final static int WINDOW_NONE = 5;private final static int WINDOW_QQ_LANUCHRE = 6;private PowerManager mPowerManager;private KeyguardManager mKeyguardManager;private KeyguardManager.KeyguardLock mKeyguardLock;private PowerManager.WakeLock mWakeLock;private boolean canGetQQMonkey = true;private AccessibilityNodeInfo mLastMonkeyNode = null;@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {int eventType = event.getEventType();Log.d(TAG, "onAccessibilityEvent: eventType=" + eventType);switch (eventType) {case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED://64 有通知List<CharSequence> notifications = event.getText();if (notifications != null) {for (CharSequence c : notifications) {String s = c.toString();Log.d(TAG, "onAccessibilityEvent: s=" + s);if (s.contains("[微信红包]") || s.contains("[QQ红包]")) {Notification notification = (Notification) event.getParcelableData();PendingIntent pendingIntent = notification.contentIntent;try {wakeUpAndUnLock(true);//亮屏并解鎖canGetMonkey = true;pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}}}}break;case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED://32String clazz = event.getClassName().toString();Log.d(TAG, "onAccessibilityEvent: clazz=" + clazz);if ("com.tencent.mm.ui.LauncherUI".equals(clazz)) {//微信消息列表页面mWindowStatus = WINDOW_LANUCHRE;getWeiXinPacket();} else if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(clazz)) {//微信抢红包页面mWindowStatus = WINDOW_RECEIVERUI;openWeiXinPacket();} else if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(clazz)) {//微信已领取红包列表页面mWindowStatus = WINDOW_DETAILUI;//performBackClick();} else if ("com.tencent.mobileqq.activity.SplashActivity".equals(clazz)) {//QQ消息列表頁面mWindowStatus = WINDOW_QQ_LANUCHRE;//getQQPacket();} else if ("cooperation.qwallet.plugin.QWalletPluginProxyActivity".equals(clazz)) {//QQ紅包頁面mWindowStatus = WINDOW_OTHER;//performBackClick();} else {mWindowStatus = WINDOW_OTHER;}break;case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED://2048if (mWindowStatus == WINDOW_LANUCHRE) {//在消息列表页面,其他页面不处理Log.d(TAG, "onAccessibilityEvent: canGetMonkey=" + canGetMonkey + " isGetMonkey=" + isGetMonkey);if (isGetMonkey) {return;}getWeiXinPacket();}if (mWindowStatus == WINDOW_QQ_LANUCHRE) {if (canGetQQMonkey) openQQPacket();}break;default:break;}}/*** 打开QQ红包*/private void openQQPacket() {Log.i(TAG, "openQQPacket: ");//com.tencent.mobileqq:id/name TextView 点击拆开AccessibilityNodeInfo rootNote = getRootInActiveWindow();if (rootNote != null) {List<AccessibilityNodeInfo> list = rootNote.findAccessibilityNodeInfosByText("QQ红包");if (list != null && !list.isEmpty()) {Log.d(TAG, "openQQPacket() list not null");for (AccessibilityNodeInfo i : list) {AccessibilityNodeInfo parent = i.getParent();if (null != findNodeInfosByText(parent, "点击拆开")) {canGetQQMonkey = fals1e;//打开红包时不去响应其他消息的事件performClick(i.getParent());}}}}canGetQQMonkey = true;}private void getQQPacket() {Log.i(TAG, "getQQPacket: ");AccessibilityNodeInfo rootNote = getRootInActiveWindow();if (rootNote != null) {AccessibilityNodeInfo recent_chat_list = findNodeInfosById(rootNote, "com.tencent.mobileqq:id/recent_chat_list");//消息列表页面if (recent_chat_list != null) {/* List<AccessibilityNodeInfo> list = recent_chat_list.findAccessibilityNodeInfosByText("[有红包][QQ红包]恭喜发财");if (list != null && !list.isEmpty()) {Log.d(TAG, "getQQPacket() list not null");AccessibilityNodeInfo note = list.get(list.size() -1);//最新的有红包的会话performClick(note);}*//*int count = recent_chat_list.getChildCount();for (int i = 0; i <count; i++) {AccessibilityNodeInfo note = recent_chat_list.getChild(i);Log.d(TAG, "getQQPacket:" + note.getText() + "--" + note.getViewIdResourceName());}*/}}}/*** 喚醒屏幕 解锁** @param unlock*/private void wakeUpAndUnLock(boolean unlock) {Log.d(TAG, "wakeUpAndUnLock() called with: unlock = [" + unlock + "]");if (unlock) {if (!mPowerManager.isScreenOn()) {//熄屏时Log.d(TAG, "wakeUpAndUnLock: wakeup");mWakeLock.acquire();mWakeLock.release();}Log.d(TAG, "wakeUpAndUnLock: isKeyguardLocked=" + mKeyguardManager.isKeyguardLocked() + " isKeyguardSecure=" + mKeyguardManager.isKeyguardSecure());if (mKeyguardManager.isKeyguardLocked() && !mKeyguardManager.isKeyguardSecure()) {mKeyguardLock.disableKeyguard();Log.d(TAG, "wakeUpAndUnLock: disableKeyguard");}} else {if (!mKeyguardManager.isKeyguardLocked()) {mKeyguardLock.reenableKeyguard();Log.d(TAG, "wakeUpAndUnLock: reenableKeyguard");}}}/*** 打开红包*/private void openWeiXinPacket() {Log.d(TAG, "openWeiXinPacket: 开始打开红包");AccessibilityNodeInfo rootNodeInfo = getRootInActiveWindow();if (rootNodeInfo == null) {return;}AccessibilityNodeInfo openTarget = null;//可以根据id 也可以根据文字来操作//com.tencent.mm:id/bg_ 看看大家的手气openTarget = findNodeInfosByText(rootNodeInfo, "看看大家的手气");Log.d(TAG, "openWeiXinPacket: openTarget=" + openTarget);if (openTarget != null) {//红包抢完了performGlobalAction(GLOBAL_ACTION_BACK);}if (openTarget == null) {for (int i = 0; i < rootNodeInfo.getChildCount(); i++) {AccessibilityNodeInfo note = rootNodeInfo.getChild(i);//可以根据id 也可以根据是否是Button.这些信息可以通过DDMS 来获取//android.widget.Button com.tencent.mm:id/bg7if ("android.widget.Button".equals(note.getClassName())) {openTarget = note;break;}}}//如果有"开"这个按钮图标就点击if (openTarget != null) {performClick(openTarget);}}/*** 准备打开红包:打开红包弹窗*/@SuppressLint("NewApi")private void getWeiXinPacket() {Log.d(TAG, "getWeiXinPacket");AccessibilityNodeInfo rootNodeInfo = getRootInActiveWindow();if (rootNodeInfo == null) {return;}List<AccessibilityNodeInfo> nodes = rootNodeInfo.findAccessibilityNodeInfosByText("领取红包");Log.d(TAG, "getWeiXinPacket nodes is null? " + (nodes == null));if (nodes != null) {if (nodes.isEmpty()) {//在好友会话列表页面AccessibilityNodeInfo info = findNodeInfosByText(rootNodeInfo, "[微信红包]");if (info != null) {canGetMonkey = true;performClick(info);Log.d(TAG, "getWeiXinPacket canGetMonkey= true");}} else {//在单个群会话页面if (canGetMonkey) {//点击最新的红包AccessibilityNodeInfo newMoney = nodes.get(nodes.size() - 1);performClick(newMoney);Log.d(TAG, "getWeiXinPacket canGetMonkey= false");canGetMonkey = false;} else {//单个会话里面接到红包时//单个会话:ListViewLog.d(TAG, "getWeiXinPacket 对话中有红包项");//单个会话列表:ListView/*AccessibilityNodeInfo messages = findNodeInfosById(rootNodeInfo,"com.tencent.mm:id/a25");if(null != messages){AccessibilityNodeInfo monkeyNode = null;AccessibilityNodeInfo monkeyopendMessNote = null;AccessibilityNodeInfo mextNote = null;isGetMonkey = true;int messageCount = messages.getChildCount();Log.d(TAG, "getWeiXinPacket: messageCount=" + messageCount);for (int i=0; i<messageCount;i++) {monkeyNode = messages.getChild(i);if(null != findNodeInfosByText(monkeyNode,"领取红包")){monkeyopendMessNote = i==messageCount-1 ?null:messages.getChild(i+1);mextNote = findNodeInfosByText(monkeyopendMessNote,"领取红包");//下一个记录还是红包项时,不领取,只领最新的那个//红包项下一项不是"你领取xx的红包"就表示当前红包没有领取monkeyopendMessNote = findNodeInfosById(monkeyopendMessNote,"com.tencent.mm:id/a3g");//头像Log.d(TAG, "getWeiXinPacket: monkeyopendMessNote=" +monkeyopendMessNote +" \n mextNote=" +mextNote);//当前记录的下一个记录不是"已领取的消息" 也不是红包消息if ( monkeyopendMessNote == null && mextNote == null) {Log.d(TAG, "getWeiXinPacket: 有未领取的红包");performClick(findNodeInfosByText(monkeyNode,"领取红包"));}else{Log.d(TAG, "getWeiXinPacket: 红包已经领取了或者不是最新的红包");}}}isGetMonkey = false;}*///保存最新的红包,在单个会话页面,只判断最新的红包是否可以抢(是否已经抢过了)isGetMonkey = true;//单个会话列表:ListView//AccessibilityNodeInfo messages = findNodeInfosById(rootNodeInfo,"com.tencent.mm:id/a25");//mLastMonkeyNode = nodes.get(nodes.size()-1);//int index = nodes.indexOf(mLastMonkeyNode);for (int i = 0; i < nodes.size(); i++) {Log.i(TAG, "getWeiXinPacket: i=" + i + " " + nodes.get(i));}isGetMonkey = false;}}}}/*** 点击指定的节点(不可以点击时点击其父节点)** @param info*/private void performClick(AccessibilityNodeInfo info) {Log.d(TAG, "performClick");if (info != null) {if (info.isClickable()) {info.performAction(AccessibilityNodeInfo.ACTION_CLICK);} else {performClick(info.getParent());}}}/*** 模拟点击back 键返回一次*/private void performBackClick() {Log.i(TAG, "performBackClick: ");performGlobalAction(GLOBAL_ACTION_BACK);}/*** 通过指定的文本查找节点** @param rootNodeInfo* @param s* @return*/private AccessibilityNodeInfo findNodeInfosByText(AccessibilityNodeInfo rootNodeInfo, String s) {//Log.d(TAG, "findNodeInfosByText() called with: s = [" + s + "]");if (rootNodeInfo != null) {List<AccessibilityNodeInfo> list = rootNodeInfo.findAccessibilityNodeInfosByText(s);if (list != null && !list.isEmpty()) {return list.get(0);}}return null;}/*** 通过指定的id查找节点** @param rootNodeInfo* @param id* @return*/private AccessibilityNodeInfo findNodeInfosById(AccessibilityNodeInfo rootNodeInfo, String id) {Log.d(TAG, "findNodeInfosById() called with: id = [" + id + "]");if (rootNodeInfo != null) {List<AccessibilityNodeInfo> list = rootNodeInfo.findAccessibilityNodeInfosByViewId(id);if (list != null && !list.isEmpty()) {return list.get(0);}}return null;}@Overridepublic void onInterrupt() {Log.i(TAG, "onInterrupt: ");}@Overrideprotected void onServiceConnected() {super.onServiceConnected();Log.d(TAG, "onServiceConnected: 抢红包服务以及开启");mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "rob_monkey_wakeup");mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);mKeyguardLock = mKeyguardManager.newKeyguardLock("rob_monkey_keyguard_lock");}@Overridepublic void onDestroy() {super.onDestroy();Log.i(TAG, "onDestroy: ");if (null != mWakeLock) {mWakeLock.release();mWakeLock = null;}}}
本文介绍了一款自动抢红包应用程序的开发过程,该应用支持在后台自动抢取微信和QQ红包,可在消息列表及聊天界面自动检测并打开红包。文章详细讲解了如何利用AccessibilityService实现功能,并提供了关键代码。
854





