android微信的抢红包插件
来源:互联网 发布:mac终端编辑保存退出 编辑:程序博客网 时间:2024/04/30 16:52
前言
之前看到了微信抢红包的插件,觉得这个功能实在强大了,这和之前我想实现的模拟点击事件基本相似,可以完美的触发一个view的点击事件,当然静默安装的原理也和抢红包的原理是一样的。
小米有开源小米的抢红包的demo,之后有童鞋在此之上增加了自己的逻辑,使其完善。现在为了学习,我也加入抢红包的demo大军哈哈,主要在于学习。
原理
原理主要是通过辅助功能AccessibilityService来完成的,AccessibilityService是Google用来帮助肢体不便的人所开发的一个功能,能够触发相应的用户事件比如点击,滑动等等。
抢红包的功能也是基于此能力之上,去进行模拟点击事件。当然,AccessibilityService的功能需要得到用户的许可,通过它的功能的介绍,已经可以知道它的强大,其实这个的能力和root相当,甚至更强,毕竟可以模拟一切的用户事件。
所以,在实现的方法前,需要了解
1. 如何获取特定能够点击的view的节点
2. 触发点击事件,进行判断
逻辑
需要注意:保持屏幕常亮,需要把每个群的消息免打扰取消,主要为了能够接收到通知Notification,在一开始请回到Home
接收到Notification之后,存入List中作为待处理红包.
逐个处理List中的PendingIntent,开启微信的聊天界面,获取可以点击的红包列表,逐个点击。
进入红包处理,两种情况,
一、进入接收红包的界面,获取抢红包的按钮,触发点击。进入红包detail界面,结束。
二、已经抢过,进入红包detail界面,或者被抢完了,停留在receive界面,结束,回到主界面。回到步骤1
工程源码
- 首先新建一个PluginService继承AccessibilityService,然后再Manifest.xml中进行注册:
<service android:name=".PluginService" 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:resource=…的是对于Service的参数配置,文件的位置在于res下的xml文件下,名字定为accessible_service_config.xml
各个参数的定义:
android:accessibilityEventTypes:允许接收的事件,这里定义为notification变化事件,窗口切换变化事件,窗口内容变化事件。
android:accessibilityFeedbackType:设置返回给用户的形式
android:packageNames:指定响应某个指定应用的事件。需要知道某个应用的包名的时候可以通过DDMS中的hierarchy view进行查看。
android:notificationTimeout:设置响应的时间
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/app_name" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowContentChanged|typeWindowStateChanged" android:accessibilityFeedbackType="feedbackAllMask" android:packageNames="com.tencent.mm" android:notificationTimeout="0" android:accessibilityFlags="" android:canRetrieveWindowContent="true"/>
2.在PluginService中进行逻辑的处理
在onAccessibilityEvent中进行事件的监听,监听包括三种类型的,一种是通知栏的变化,一种是窗口内容的变化,一种是窗口切换的变化。
@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) { int eventType = event.getEventType(); switch (eventType) { // 监听通知栏消息 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: handlerNotification(event); break; // 监听窗口变化消息 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: handlerWindowStateChange(event); break; // 监听窗口内容的动态变化 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: handlerWindowContentChange(event); break; default: break; }}
3.我们回到了主界面,有群发了红包,那么进入notification变化的事件中去,在其中判断是否是含有红包的消息,如果是的话则模拟打开notification,这里多做了一个步奏就是将多个notification存储到一个list里面,进行足一的打开。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)public void handlerNotification(AccessibilityEvent event) { if (event == null) return; List<CharSequence> contents = event.getText(); if (contents != null && !contents.isEmpty()) { for (CharSequence content : contents) { String text = content.toString(); if (!text.contains("[微信红包]")) continue; if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) { Notification notification = (Notification) event.getParcelableData(); PendingIntent pendingIntent = notification.contentIntent; Log.e("pendingintent", pendingIntent.getCreatorPackage().toString()); if (pendingIntent.getCreatorPackage().toString().equals("com.tencent.mm")) { if ((curStatus != Status.ON_CHAT_ROOM || curStatus != Status.ON_LUCKY_MONEY_RECEIVED) && untreatedLuckyMoneyList.size() == 0) { openNotification(pendingIntent); } else { untreatedLuckyMoneyList.add(0, pendingIntent); } } } } }}/** * 开启Notification中所指向的微信聊天页面 * * @param pendingIntent */public void openNotification(PendingIntent pendingIntent) { if (pendingIntent == null) return; // 模拟点击了notification try { pendingIntent.send(); curStatus = Status.ON_CHAT_ROOM; } catch (PendingIntent.CanceledException e) { e.printStackTrace(); }}
4.一下方法通过判定窗口变化的具体的类来判定进入了哪一个界面。从而进行对应的操作。
a 进入了聊天界面,则进行领取红包的字样遍历,同时进行模拟点击开启。
b 进入领取红包界面,则遍历得到拆红包字样的节点,同时模拟点击
c 进入红包详情界面,则模拟返回键退出。
要知道具体的类是什么的时候,可以通过测试输出消息,通过event.getClassName().toString()的输出查看具体的类名。
public void handlerWindowStateChange(AccessibilityEvent event) { if (event == null || event.getSource() == null) return; String className = event.getClassName().toString(); // 微信主界面 com.tencent.mm.ui.LauncherUI if (className.equals("com.tencent.mm.ui.LauncherUI")) { curStatus = Status.ON_CHAT_ROOM; if (canOpenNode == null) { canOpenNode = event.getSource().findAccessibilityNodeInfosByText("领取红包"); trashOpenNode = new ArrayList<AccessibilityNodeInfo>(); } openLuckyMoney(); // 红包接收界面 com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI } else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) { curStatus = Status.ON_LUCKY_MONEY_RECEIVED; unpackLuckyMoney(event.getSource()); // 红包的detail界面 com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI } else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) { curStatus = Status.ON_LUCKY_MONEY_DETAIL; back(); } }
5.进入到微信的聊天界面,这时候会触发窗口变化消息,这时候通过view找到具有领取红包字样的节点,如果有,则进行模拟点击,如果没有回到主界面。这里其中一个步奏也是将多个具有领取红包的节点存储到list中,等待开启。
/** * 在聊天界面中打开红包 */public void openLuckyMoney() { if (canOpenNode != null && canOpenNode.size() == 0) { backToHome(); disposeLuckyMoneyList(); canOpenNode = null; trashOpenNode = null; } if (canOpenNode == null) { backToHome(); return; } AccessibilityNodeInfo node = canOpenNode.remove(0); trashOpenNode.add(node); if (node.getParent() != null && node.getParent().isClickable()) { node.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK); }}
6.假如进入到了红包领取界面,则需要先判断是否被领取完了,或者是过期了,如果都不是,则找到拆红包字样的节点进行模拟点击
public void unpackLuckyMoney(AccessibilityNodeInfo nodeInfo) { if (nodeInfo == null) { back(); return; } // 打开红包,如果红包已被抢完,遍历节点, 如果匹配“红包详情”、“手慢了”和“过期”,则返回 // 继续打开其他红包 List<AccessibilityNodeInfo> packedLists = new ArrayList<>(); packedLists.addAll(nodeInfo.findAccessibilityNodeInfosByText("红包详情")); packedLists.addAll(nodeInfo.findAccessibilityNodeInfosByText("手慢了")); packedLists.addAll(nodeInfo.findAccessibilityNodeInfosByText("过期")); if (!packedLists.isEmpty()) { back(); return; } List<AccessibilityNodeInfo> unPackedLists = nodeInfo.findAccessibilityNodeInfosByText("拆红包"); if (unPackedLists.isEmpty()) { back(); } else { AccessibilityNodeInfo node = unPackedLists.get(0); node.performAction(AccessibilityNodeInfo.ACTION_CLICK); } }
7.当进入到了红包详情页面时候,则进行返回,返回到聊天界面之后,会继续进行红包列表进行拆红包,知道拆完了所有的红包之后,就会退回到主界面,然后继续拆开notification list中的消息,如果没有消息,则等待。
改进
通过遍历节点去找到能点击的事件是比较浪费效率的,其实通过DDMS中的hierarchy view可以看到每个控件的ID,通过ID可以直接获取该控件,然后模拟点击,就不用进行遍历了。
项目源码,github网址
参考文档网址
参考工程
- android微信的抢红包插件
- Android AccessibilityService 微信红包插件
- android 微信红包
- Android实现微信自动抢红包的程序
- Android实现微信自动抢红包的程序
- 基于微信红包插件的原理实现android任何APP自动发送评论(已开源)
- android实现微信自动抢红包
- 参考微信红包的抢红包算法
- android抢红包插件的实现
- 微信插件制作之抢红包入门篇
- qq微信红包抢红包神器
- 利用AccessibilityService实现“微信红包”插件
- 微信红包的算法
- 微信,QQ 抢红包
- 微信自动抢红包
- 微信6.53抢红包
- 使用Android辅助服务AccessibilityService实现的微信自动抢红包的小程序
- Android 通过AccessibilityService实现微信自动抢红包时如何过滤已抢红包
- CentOS x64上Matlab R2015b的镜像安装方法与卸载
- C++学习笔记-IO类
- elasticsearch 后置过滤器(Post Filter)
- NBUT 1223 Friends number
- Lowest Common Multiple Plus 求n个数的最小公倍数
- android微信的抢红包插件
- 2324: [ZJOI2011]营救皮卡丘
- 关于JavaScript中的DOM操作
- Java笔记 第二章 Java语法基础
- c#编写部署windows服务
- html图片下边显示文字
- Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
- hdu1494(好题 DP%)
- springMVC用MyEclipse配置的简单小例子