写在前面
眼看快过年了,先祝大家新年快乐,本篇是今年最后一篇文章,想想过年到了,微信红包肯定少不了,但是每次都是比人家慢了一步,所以上网搜了一下,确实很多自动抢红包的,但是担心有一些流氓软件存在一些后门,所以还是决定自己撸一遍,其实在半年前就已经实现过类似的功能,这次权当整理了;
环境要求
微信 v6.5.4
前提工作
在开始编码前我们需要弄清楚微信的某个具体布局的view id是多少,这里我用的是android studio自带的分析工具,很好用,手机到了你要分析的页面后,点击AS的Tools->Android->Android Device Monitor;
在你连上手机后点击Dump view Hierarchy for UI Automator后会出来一个和你手机上一样的界面,点击某个view之后会有对应的text、resource-id,我们需要通过text或者resource-id去实现自动点击,下面对应的属性是checked表示这个view是否可以点击,下面类似的是android的基础知识就不一一解释了,分析好所有页面后开始编码;
开始编码
首选在res文件夹下新建xml文件夹,然后新建xml文件,名字随意,只要后面写在AndroidManifest.xml中对应一样即可,例:
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric" android:canRetrieveWindowContent="true" android:description="@string/accessibility_description" android:notificationTimeout="100" android:packageNames="com.tencent.mm" /> |
其实看字段应该能看懂什么意思notificationTimeout是通知超时时间,packageNames是你要监听的应用包名,其它的就不一一介绍了;
接下来新建一个extends AccessibilityService的service类,然后我们在onAccessibilityEvent函数中做文章:
我们可以通过event.getEventType();拿到事件的类型,例:
1 2 3 4 5 6 7 8 9 10 11 12 | int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: // 通知栏事件 break; case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: //窗体状态改变 break; case AccessibilityEvent.TYPE_VIEW_SCROLLED: //滚动 break; } |
好吧,都是很简单的功能,我觉得不必要一点点去讲解代码了,后面会给出源码下载地址,这里我讲一下实现思路:
1、手机解锁(如果是锁屏的情况下,必须要无密码)
2、点击通知栏
3、点击红包item
4、开启红包
5、锁屏(如果刚开始是锁屏的情况下)
步骤不多,可以说比较清晰简单的;
下面给出全部代码,例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | public class QinagHongBaoServier extends AccessibilityService { private static final String TAG = "Jackie"; /** * 微信的包名 */ private static final String WECHAT_PACKAGENAME = "com.tencent.mm"; /** * 红包消息的关键字 */ private static final String ENVELOPE_TEXT_KEY = "[微信红包]"; /** * 在单人或者群聊页面,默认可以点击,也就是可以监听view的变化 */ private boolean CHAT_PAGE_CLICK = true; /** * 判断是不是消息通知栏点击进来的 */ private boolean NOTIFICATION_CLICK = false; /** * 判断是否锁屏 */ private boolean LOCKED = false; @Override public void onAccessibilityEvent(AccessibilityEvent event) { int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知栏事件 if (isScreenLocked()) { //判断是否锁屏 是的话解锁 LOCKED = true; wakeAndUnlock(); } List<CharSequence> texts = event.getText(); if (!texts.isEmpty()) { for (CharSequence t : texts) { String text = String.valueOf(t); if (text.contains(ENVELOPE_TEXT_KEY)) { NOTIFICATION_CLICK = true; openNotification(event); break; } } } break; case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED://窗体状态改变 //窗体发生变化 if (CHAT_PAGE_CLICK && NOTIFICATION_CLICK) { openEnvelope(event); } break; case AccessibilityEvent.TYPE_VIEW_SCROLLED: if (CHAT_PAGE_CLICK && NOTIFICATION_CLICK) { openEnvelope(event); } break; } } @Override public void onInterrupt() { } /** * 打开通知栏消息 */ private void openNotification(AccessibilityEvent event) { if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) { Notification notification = (Notification) event.getParcelableData(); PendingIntent pendingIntent = notification.contentIntent; try { pendingIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void openEnvelope(AccessibilityEvent event) { if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(event.getClassName())) { //点中了红包,下一步就是去拆红包222222 checkKey1(); } else if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(event.getClassName())) { //拆完红包后看详细的纪录界面33333 //拆完啦 Toast.makeText(this, "抢完啦", Toast.LENGTH_SHORT).show(); //设置不监听单人聊天页面监听 CHAT_PAGE_CLICK = false; //把标识设回原来的状态 NOTIFICATION_CLICK = false; //模拟点击返回 onBackButton(); //抢完红包返回一秒内不点击,为了绕开返回监听到view变化又TM给点进来了 Handler handler = new Handler(); handler.postDelayed(runnable, 1000); //锁屏 releaseLocked(); } else if ("android.widget.ListView".equals(event.getClassName())) { //在聊天界面,去点中红包11111 checkKey2(); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private void checkKey1() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if (nodeInfo == null) { Log.w(TAG, "rootWindow为空"); return; } // List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/bi3"); for (AccessibilityNodeInfo n : list) { n.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private void checkKey2() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if (nodeInfo == null) { Log.w(TAG, "rootWindow为空"); return; } List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("领取红包"); if (list.size() > 0) { //领取最新的红包 for (int i = list.size() - 1; i >= 0; i--) { AccessibilityNodeInfo parent = list.get(i).getParent(); if (parent != null) { parent.performAction(AccessibilityNodeInfo.ACTION_CLICK); break; } } } } private Runnable runnable = new Runnable() { @Override public void run() { CHAT_PAGE_CLICK = true; Log.i("xxxxxxxx", "我变回来啦"); } }; /** * 点击back返回,TMD,模拟back按键不知道为什么失败了,反正微信界面有back点击它也一样,可能就响应速度有点差别 */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private void onBackButton() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if (nodeInfo != null) { List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/gw"); if (list.size() > 0) { list.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } /** * 回到系统桌面 */ private void back2Home() { Intent home = new Intent(Intent.ACTION_MAIN); home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); home.addCategory(Intent.CATEGORY_HOME); startActivity(home); } /** * 系统是否在锁屏状态 * * @return */ private boolean isScreenLocked() { KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); return keyguardManager.inKeyguardRestrictedInputMode(); } /** * 解锁手机 */ private KeyguardManager.KeyguardLock kl; private void wakeAndUnlock() { //获取电源管理器对象 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"); //点亮屏幕 wl.acquire(1000); //得到键盘锁管理器对象 KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); kl = km.newKeyguardLock("unLock"); //解锁 kl.disableKeyguard(); } /** * 重新锁屏 */ private void releaseLocked() { if (LOCKED && kl != null) { android.util.Log.d("maptrix", "release the lock"); //得到键盘锁管理器对象 kl.reenableKeyguard(); LOCKED = false; } } } |
最后记得在AndroidManifest.xml中加入权限等,例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <application android:allowBackup="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".QinagHongBaoServier" android:enabled="true" android:exported="true" android:label="@string/app_name" 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/envelope_service_config" /> </service> </application> |
测试抢红包
到设置里打开你前面对应的无障碍服务,一般是在更多设置->无障碍->你的服务名称,开启即可;
总结
OK,大功告成,功能还是很简单的,基于这种无障碍服务可以做很多事情(当然,包括一些流氓行为,或者可以微信自动不断搜索添加好友等,这个比较有利于微商吧),好了,文章先到这里,如果自己实现起来确实有问题的,可以下载demo查看;