├── .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 | 
16 |
17 | ======================
18 | 微信红包插件,简单、安全。
19 |
20 | 注意:
21 |
22 | Android系统4.1以上、微信版本6.3.28及以上。
23 |
24 | 此app安装后,请在手机“设置---辅助服务”(可能有些手机不是这样称呼),开启“微信红包插件”服务才能提醒有微信红包。
25 | 如下图:
26 |
27 | 
28 | 
29 | 
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 |
--------------------------------------------------------------------------------