android微信的抢红包插件
2015-12-21 01:07
573 查看
前言
之前看到了微信抢红包的插件,觉得这个功能实在强大了,这和之前我想实现的模拟点击事件基本相似,可以完美的触发一个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中进行事件的监听,监听包括三种类型的,一种是通知栏的变化,一种是窗口内容的变化,一种是窗口切换的变化。
@Override public 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网址
参考文档网址参考工程
相关文章推荐
- php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
- 关于php微信订阅号开发之token验证后自动发送消息给订阅号但是没有消息返回的问题
- 微信相关的请求
- 处理微信服务器发来的消息
- android微信支付(问题总结)
- Android 超高仿微信图片多选、单选,图片剪切,图片预览,拍照等功能
- 浦发银行微信支付/绑定状态异常,请解绑后重新绑定
- 关于微信开发与微信支付更新
- 微信分享及授权登录
- 微信公众平台开发(110) 微信连Wi-Fi
- JAVA版微信支付V3-完全版
- 微信公众平台开发(109) 个性化菜单
- cordova(phonegap) 微信以及QQ分享插件
- 响应微信公众平台公众号菜单单击事件
- 微信企业号应用回调模式开启
- 微信JS SDK Demo
- 微信公众平台PHP示例一
- 微信WeixinJSBridge API使用实例
- 支付宝支付 微信支付的小坑(2)
- CSDN博客QQ加群、微信