├── .classpath ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── README.md ├── assets └── luckymoney_sound.ogg ├── libs └── android-support-v4.jar ├── pic ├── wrp1.png ├── wrp2.png ├── wrp3.png └── wrp4.png ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml ├── values │ ├── strings.xml │ └── styles.xml └── xml │ └── accessibility.xml └── src └── com └── nicksong └── luckymoney └── RedPacket.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | WechatRedPacket 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 15 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WechatRedPacket 2 | Android:实现监听微信红包,并自动抢红包,春节必不可少[PS:微信消息需打开通知栏提示]。 3 | 4 | 原理: 5 | 6 | 利用AccessibilityService这个辅助服务类,监听通知栏微信消息,如果有微信红包,就模拟界面一些控件的点击事件。 7 | 可能大家会问:如何模拟界面上的控件点击事件呢? 8 | 问得好。 9 | 10 | 这里可以用到ADT里的uiautomatorviewer工具,可以清晰地看到每个界面每个控件的属性,如控件类型(是Button,还是ImageView,或者是TextView……)、 11 | clickable的值是否可点击等;还会用到AccessibilityService类中getRootInActiveWindow这个方法,来获取这个界面。 12 | 13 | 了解详细讲解,请关注博客[http://blog.csdn.net/weiren1101/article/details/53112439](http://blog.csdn.net/weiren1101/article/details/53112439) 14 | 15 | ![原理图](https://github.com/Ericsongyl/WechatRedPacket/blob/master/pic/wrp1.png) 16 | 17 | ====================== 18 | 微信红包插件,简单、安全。 19 | 20 | 注意: 21 | 22 | Android系统4.1以上、微信版本6.3.28及以上。 23 | 24 | 此app安装后,请在手机“设置---辅助服务”(可能有些手机不是这样称呼),开启“微信红包插件”服务才能提醒有微信红包。 25 | 如下图: 26 | 27 | ![](https://github.com/Ericsongyl/WechatRedPacket/blob/master/pic/wrp2.png) 28 | ![](https://github.com/Ericsongyl/WechatRedPacket/blob/master/pic/wrp3.png) 29 | ![](https://github.com/Ericsongyl/WechatRedPacket/blob/master/pic/wrp4.png) 30 | -------------------------------------------------------------------------------- /assets/luckymoney_sound.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/assets/luckymoney_sound.ogg -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/libs/android-support-v4.jar -------------------------------------------------------------------------------- /pic/wrp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/pic/wrp1.png -------------------------------------------------------------------------------- /pic/wrp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/pic/wrp2.png -------------------------------------------------------------------------------- /pic/wrp3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/pic/wrp3.png -------------------------------------------------------------------------------- /pic/wrp4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/pic/wrp4.png -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ericsongyl/WechatRedPacket/2d8d0db6ff6fc9d962d7f8674a1c74cffed9ecf0/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 微信红包插件 4 | accessibilityDemo 5 | WebChat Get RedMoney 6 | 7 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /res/xml/accessibility.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /src/com/nicksong/luckymoney/RedPacket.java: -------------------------------------------------------------------------------- 1 | package com.nicksong.luckymoney; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import android.accessibilityservice.AccessibilityService; 6 | import android.annotation.SuppressLint; 7 | import android.app.Notification; 8 | import android.app.PendingIntent; 9 | import android.app.PendingIntent.CanceledException; 10 | import android.content.res.AssetFileDescriptor; 11 | import android.content.res.AssetManager; 12 | import android.media.MediaPlayer; 13 | import android.util.Log; 14 | import android.view.accessibility.AccessibilityEvent; 15 | import android.view.accessibility.AccessibilityNodeInfo; 16 | 17 | public class RedPacket extends AccessibilityService { 18 | 19 | private MediaPlayer player; 20 | private boolean isFirst = false; 21 | 22 | @Override 23 | public void onAccessibilityEvent(AccessibilityEvent event) { 24 | int eventType = event.getEventType(); 25 | switch (eventType) { 26 | //第一步:监听通知栏消息 27 | case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: 28 | List texts = event.getText(); 29 | if (!texts.isEmpty()) { 30 | for (CharSequence text : texts) { 31 | String content = text.toString(); 32 | Log.i("demo", "text:"+content); 33 | if (content.contains("[微信红包]")) { 34 | isFirst = true; 35 | playSound4LuckyMoneyComing(); 36 | //模拟打开通知栏消息 37 | if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) { 38 | Notification notification = (Notification) event.getParcelableData(); 39 | PendingIntent pendingIntent = notification.contentIntent; 40 | try { 41 | pendingIntent.send(); 42 | } catch (CanceledException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | break; 50 | //第二步:监听是否进入微信红包消息界面 51 | case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: 52 | String className = event.getClassName().toString(); 53 | if (className.equals("com.tencent.mm.ui.LauncherUI")) { 54 | Log.i("demo", "开始抢红包"); 55 | //开始抢红包 56 | getPacket(); 57 | } else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) { 58 | Log.i("demo", "开始拆红包"); 59 | isFirst = false; 60 | //开始打开红包 61 | openPacket(); 62 | } 63 | // else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) { 64 | // Log.i("demo", "在红包详情直接返回"); 65 | // //模拟点击返回 66 | // goBackFromLmUi(); 67 | // } 68 | break; 69 | } 70 | } 71 | 72 | /** 73 | * 在红包详情界面模拟返回 74 | */ 75 | private void goBackFromLmUi() { 76 | isFirst = false; 77 | AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); 78 | if (nodeInfo != null) { 79 | for (int i = 0; i < nodeInfo.getChildCount(); i++) { 80 | Log.i("demo", "goBackFromLmUi i = " + i); 81 | Log.i("demo", "goBackFromLmUi Click"+",isClickable:" + nodeInfo.getChild(i).isClickable()); 82 | Log.i("demo", "goBackFromLmUi View type = " + nodeInfo.getChild(i).getClassName()); 83 | if ("android.widget.LinearLayout".equals(nodeInfo.getChild(i).getClassName()) && nodeInfo.getChild(i).isClickable()) { 84 | nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK); 85 | } 86 | } 87 | } 88 | } 89 | 90 | /** 91 | * 查找到 92 | */ 93 | @SuppressLint("NewApi") 94 | private void openPacket() { 95 | AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); 96 | if (nodeInfo != null) { 97 | for (int i = 0; i < nodeInfo.getChildCount(); i++) { 98 | Log.i("demo", "openPacket i = " + i); 99 | Log.i("demo", "Click"+",isClickable:" + nodeInfo.getChild(i).isClickable()); 100 | Log.i("demo", "View type = " + nodeInfo.getChild(i).getClassName()); 101 | if ("android.widget.Button".equals(nodeInfo.getChild(i).getClassName()) && nodeInfo.getChild(i).isClickable()) { 102 | nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK); 103 | } 104 | } 105 | } 106 | 107 | } 108 | 109 | @SuppressLint("NewApi") 110 | private void getPacket() { 111 | AccessibilityNodeInfo rootNode = getRootInActiveWindow(); 112 | recycle(rootNode); 113 | } 114 | 115 | /** 116 | * 打印一个节点的结构 117 | * @param info 118 | */ 119 | @SuppressLint("NewApi") 120 | public void recycle(AccessibilityNodeInfo info) { 121 | if (info.getChildCount() == 0) { 122 | if(info.getText() != null){ 123 | if("领取红包".equals(info.getText().toString())){ 124 | //这里有一个问题需要注意,就是需要找到一个可以点击的View 125 | Log.i("demo", "Click"+",isClick:"+info.isClickable()); 126 | info.performAction(AccessibilityNodeInfo.ACTION_CLICK); 127 | AccessibilityNodeInfo parent = info.getParent(); 128 | while(parent != null){ 129 | Log.i("demo", "parent isClick:"+parent.isClickable()); 130 | if(parent.isClickable() && isFirst){ 131 | parent.performAction(AccessibilityNodeInfo.ACTION_CLICK); 132 | break; 133 | } 134 | parent = parent.getParent(); 135 | } 136 | 137 | } 138 | } 139 | 140 | } else { 141 | for (int i = 0; i < info.getChildCount(); i++) { 142 | if(info.getChild(i)!=null){ 143 | recycle(info.getChild(i)); 144 | } 145 | } 146 | } 147 | } 148 | 149 | @Override 150 | public void onInterrupt() { 151 | } 152 | 153 | private void playSound4LuckyMoneyComing() { 154 | try { 155 | AssetManager assetManager = this.getAssets(); 156 | AssetFileDescriptor aFileDescriptor = assetManager.openFd("luckymoney_sound.ogg"); 157 | player = new MediaPlayer(); 158 | player.setDataSource(aFileDescriptor.getFileDescriptor(), aFileDescriptor.getStartOffset(), aFileDescriptor.getLength()); 159 | player.prepare(); 160 | player.start(); 161 | } catch (IOException e) { 162 | // TODO Auto-generated catch block 163 | e.printStackTrace(); 164 | } 165 | } 166 | 167 | } 168 | --------------------------------------------------------------------------------