教你一步步實(shí)現(xiàn)Android微信自動(dòng)搶紅包
本文介紹微信自動(dòng)搶紅包的實(shí)現(xiàn)方法,主要實(shí)現(xiàn)以下幾個(gè)功能:
1.自動(dòng)拆開屏幕上出現(xiàn)的紅包
2.處于桌面或聊天列表時(shí)接收到紅包信息時(shí)自動(dòng)進(jìn)入聊天界面并拆紅包
3.日志功能,記錄搶紅包的詳細(xì)日志
實(shí)現(xiàn)原理
1.利用AccessibilityService輔助服務(wù),監(jiān)測屏幕內(nèi)容,實(shí)現(xiàn)自動(dòng)拆紅包的目的。
2.利用ActiveAndroid數(shù)據(jù)庫簡單記錄紅包日志
3.利用preference實(shí)現(xiàn)監(jiān)控選項(xiàng)紀(jì)錄
最終界面
搶紅包核心代碼
AccessibilityService配置
android:accessibilityEventTypes
設(shè)置觸發(fā)監(jiān)聽回調(diào)的事件類型;
android:packageNames
設(shè)置監(jiān)聽的應(yīng)用,這里監(jiān)聽的是微信,因此填上微信的包名com.tencent.mm
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_description" android:notificationTimeout="100" android:packageNames="com.tencent.mm" android:settingsActivity="com.oden.annotations.app.activity.ManActivity" />
在AndroidManifest.xml中聲明:
<service android:name=".app.service.HongbaoService_" 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/accessibility_service_config" /> </service>
搶紅包實(shí)現(xiàn)代碼
接收系統(tǒng)發(fā)送來的AccessibilityEvent
private static final String GET_RED_PACKET = "領(lǐng)取紅包"; private static final String CHECK_RED_PACKET = "查看紅包"; private static final String RED_PACKET_PICKED = "手慢了,紅包派完了"; private static final String RED_PACKET_PICKED2 = "手氣"; private static final String RED_PACKET_PICKED_DETAIL = "紅包詳情"; private static final String RED_PACKET_SAVE = "已存入零錢"; private static final String RED_PACKET_NOTIFICATION = "[微信紅包]"; @Override public void onAccessibilityEvent(AccessibilityEvent event) { L.d("RECEIVE EVENT!"); if (watchedFlags == null) return; /* 檢測通知消息 */ if (!mMutex) { if (watchedFlags.get("pref_watch_notification") && watchNotifications(event)) return; if (watchedFlags.get("pref_watch_list") && watchList(event)) return; } if (!watchedFlags.get("pref_watch_chat")) return; this.rootNodeInfo = event.getSource(); if (rootNodeInfo == null) return; mReceiveNode = null; mUnpackNode = null; checkNodeInfo(); /* 如果已經(jīng)接收到紅包并且還沒有戳開 */ if (mLuckyMoneyReceived && !mLuckyMoneyPicked && (mReceiveNode != null)) { mMutex = true; AccessibilityNodeInfo cellNode = mReceiveNode; cellNode.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK); mLuckyMoneyReceived = false; mLuckyMoneyPicked = true; L.d("正在打開!"); } /* 如果戳開但還未領(lǐng)取 */ if (mNeedUnpack && (mUnpackNode != null)) { AccessibilityNodeInfo cellNode = mUnpackNode; cellNode.performAction(AccessibilityNodeInfo.ACTION_CLICK); mNeedUnpack = false; L.d("正在領(lǐng)??!"); } if (mNeedBack) { performGlobalAction(GLOBAL_ACTION_BACK); mMutex = false; mNeedBack = false; L.d("正在返回!"); //總次數(shù)和金額統(tǒng)計(jì) if (isGetMoney) { T.showShort(this, "搶到一個(gè)紅包: " + gotMoney + "元!"); totalMoney = totalMoney + gotMoney; totalSuccessNum++; myPrefs.totalMoney().put(totalMoney); myPrefs.successNum().put(totalSuccessNum); L.d("totalMoney: " + totalMoney); L.d("totalSuccessNum: " + totalSuccessNum); saveToLog(hongbaoInfo); isGetMoney = false; } } }
檢測監(jiān)聽事件的節(jié)點(diǎn)信息
private void checkNodeInfo() { L.d("checkNodeInfo!"); if (this.rootNodeInfo == null) return; /* 聊天會(huì)話窗口,遍歷節(jié)點(diǎn)匹配“領(lǐng)取紅包”和"查看紅包" */ List<AccessibilityNodeInfo> nodes1 = this.findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[]{ GET_RED_PACKET, CHECK_RED_PACKET}); if (!nodes1.isEmpty()) { L.d("!nodes1.isEmpty()"); AccessibilityNodeInfo targetNode = nodes1.get(nodes1.size() - 1); if ("android.widget.LinearLayout".equals(targetNode.getParent().getClassName()))//避免被文字干擾導(dǎo)致外掛失效 { if (this.signature.generateSignature(targetNode)) { mLuckyMoneyReceived = true; mReceiveNode = targetNode; L.d("signature:" + this.signature.toString()); } } else { L.d("this is text"); } return; } List<AccessibilityNodeInfo> nodes2 = this.findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[]{ "拆紅包"}); if (!nodes2.isEmpty()) { L.d("node2 != null"); for (AccessibilityNodeInfo nodeInfo : nodes2) { if (nodeInfo.getClassName().equals("android.widget.Button")) nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } else { /* 戳開紅包,紅包還沒搶完,遍歷節(jié)點(diǎn)匹配“拆紅包” */ AccessibilityNodeInfo node2 = (this.rootNodeInfo.getChildCount() > 3) ? this.rootNodeInfo.getChild(3) : null; if (node2 != null && node2.getClassName().equals("android.widget.Button")) { mUnpackNode = node2; mNeedUnpack = true; isToGetMoney = true; L.d("find red packet!"); return; } } /* 戳開紅包,紅包已被搶完,遍歷節(jié)點(diǎn)匹配“已存入零錢”和“手慢了” */ if (mLuckyMoneyPicked) { List<AccessibilityNodeInfo> nodes3 = this.findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[]{ RED_PACKET_PICKED, RED_PACKET_SAVE, RED_PACKET_PICKED2, RED_PACKET_PICKED_DETAIL}); if (!nodes3.isEmpty()) { L.d("!nodes3.isEmpty()"); if (rootNodeInfo.getChildCount() > 1) { L.d("RED_PACKET_PICKED!"); } else { L.d("nodes3.get(0).toString(): " + nodes3.get(0).getText().toString()); if (!nodes3.get(0).getText().toString().equals(RED_PACKET_PICKED_DETAIL)) { AccessibilityNodeInfo targetNode = nodes3.get(nodes3.size() - 1); hongbaoInfo.getInfo(targetNode); if (isToGetMoney) { isGetMoney = true; isToGetMoney = false; gotMoney = hongbaoInfo.getMoney(); L.d("gotMoney: " + gotMoney); } L.d("RED_PACKET_SAVE!"); L.d("hongbaoInfo: " + hongbaoInfo.toString()); } else { L.d("this packet is myself!"); } } mNeedBack = true; mLuckyMoneyPicked = false; } } }
主要通過檢測“領(lǐng)取紅包”等關(guān)鍵文字信息來判斷是否有新紅包
檢測收到紅包時(shí)判斷是否"android.widget.LinearLayout
",屏蔽聊天信息中的文字干擾
拆紅包時(shí),由于微信版本可能不同,同時(shí)進(jìn)行兩種判斷,以兼容部分版本
拆完紅包需自動(dòng)返回,有以下幾種情況:搶到了,手慢了,以及該紅包是自己發(fā)出的紅包
下面是監(jiān)聽聊天列表的代碼:
private boolean watchList(AccessibilityEvent event) { // Not a message if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || event.getSource() == null) return false; List<AccessibilityNodeInfo> nodes = event.getSource().findAccessibilityNodeInfosByText(RED_PACKET_NOTIFICATION); if (!nodes.isEmpty()) { AccessibilityNodeInfo nodeToClick = nodes.get(0); CharSequence contentDescription = nodeToClick.getContentDescription(); if (contentDescription != null && !lastContentDescription.equals(contentDescription)) { nodeToClick.performAction(AccessibilityNodeInfo.ACTION_CLICK); lastContentDescription = contentDescription.toString(); return true; } } return false; }
下面是監(jiān)聽通知信息的代碼:
private boolean watchNotifications(AccessibilityEvent event) { // Not a notification if (event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) return false; // Not a hongbao String tip = event.getText().toString(); if (!tip.contains(RED_PACKET_NOTIFICATION)) return true; Parcelable parcelable = event.getParcelableData(); if (parcelable instanceof Notification) { Notification notification = (Notification) parcelable; try { notification.contentIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } return true; }
紅包信息的獲取,及日志的存儲(chǔ)
通過獲取節(jié)點(diǎn)的子信息,分別獲得紅包發(fā)送者及搶到的金額、搶紅包時(shí)間等信息,建立簡單的表單分別記錄該信息。
@Table(name = "HongbaoInfos") public class HongbaoInfo extends Model { private int month; private int day; private int hour; private int min; private int sec; @Column(name = "sender") public String sender; @Column(name = "money") public String money; @Column(name = "time") public String time; public void getInfo(AccessibilityNodeInfo node) { AccessibilityNodeInfo hongbaoNode = node.getParent(); sender = hongbaoNode.getChild(0).getText().toString(); money = hongbaoNode.getChild(2).getText().toString(); time = getStringTime(); } private String getStringTime() { Calendar c = Calendar.getInstance(); month = c.get(Calendar.MONTH) + 1; day = c.get(Calendar.DAY_OF_MONTH); hour = c.get(Calendar.HOUR_OF_DAY); min = c.get(Calendar.MINUTE); sec = c.get(Calendar.SECOND); return month+"月"+day+"日 "+hour+":"+min+":"+sec; } @Override public String toString() { return "HongbaoInfo [sender=" + sender + ", money=" + money + ", time=" + time + "]"; } public static List<HongbaoInfo> getAll() { return new Select() .from(HongbaoInfo.class) .orderBy("Id ASC") .execute(); } public static void deleteALL() { new Delete().from(HongbaoInfo.class).execute(); } public float getMoney() { return Float.parseFloat(money); } public String getSender() { return sender; } public String getTime() { return time; } }
存儲(chǔ)操作:
private void saveToLog(HongbaoInfo hongbaoInfo) { if (watchedFlags.get("pref_etc_log")) { HongbaoInfo hongbaoInfo1 = new HongbaoInfo(); hongbaoInfo1 = hongbaoInfo; hongbaoInfo1.save(); } else { L.d("log closed!"); } }
總結(jié)
主要的代碼到這里基本結(jié)束,目前在微信最新版上測試ok,尚還存在以下幾個(gè)問題:
1.同一個(gè)人連續(xù)發(fā)的不能自動(dòng)搶,因?yàn)闉榱朔乐怪貜?fù)點(diǎn)擊做了過濾,同一個(gè)人的紅包搶了后不會(huì)再次點(diǎn)擊
2.AccessibilityService
開啟時(shí)間長后有時(shí)會(huì)被系統(tǒng)關(guān)掉
結(jié)束語
以上就是本文的全部內(nèi)容了,希望對大家的學(xué)習(xí)和工作能有所幫助。
- java模擬微信搶紅包的實(shí)例代碼
- IOS 實(shí)現(xiàn)微信自動(dòng)搶紅包(非越獄IPhone)
- 詳解利用redis + lua解決搶紅包高并發(fā)的問題
- js仿微信搶紅包功能
- laravel框架實(shí)現(xiàn)后臺(tái)登錄、退出功能示例
- Laravel框架實(shí)現(xiàn)即點(diǎn)即改功能的方法分析
- laravel 實(shí)現(xiàn)用戶登錄注銷并限制功能
- 利用laravel+ajax實(shí)現(xiàn)文件上傳功能方法示例
- laravel框架關(guān)于搜索功能的實(shí)現(xiàn)
- Laravel框架實(shí)現(xiàn)利用中間件進(jìn)行操作日志記錄功能
- Laravel框架實(shí)現(xiàn)搶紅包功能示例
相關(guān)文章
Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實(shí)現(xiàn)
這篇文章主要介紹了Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Android中HttpURLConnection類使用介紹
早些時(shí)候其實(shí)我們都習(xí)慣性使用HttpClient,但是后來Android6.0之后不再支持HttpClient,需要添加Apache的jar才行,所以,就有很多開發(fā)者放棄使用HttpClient了,HttpURLConnection畢竟是標(biāo)準(zhǔn)Java接口(java.net) ,適配性還是很強(qiáng)的2022-12-12Android實(shí)現(xiàn)界面左右滑動(dòng)切換功能
相信大家一定都使用過手機(jī)QQ和微信之類的軟件,當(dāng)我們使用時(shí)不難發(fā)現(xiàn)其界面的切換不僅可以通過點(diǎn)擊頁標(biāo)簽來實(shí)現(xiàn),還可以通過左右滑動(dòng)來實(shí)現(xiàn)的,下面小編給大家介紹下如何實(shí)現(xiàn)這個(gè)功能2016-12-12Android 使用Zbar實(shí)現(xiàn)掃一掃功能
這篇文章主要介紹了Android 使用Zbar實(shí)現(xiàn)掃一掃功能,本文用的是Zbar實(shí)現(xiàn)掃一掃,因?yàn)楦鶕?jù)本人對兩個(gè)庫的使用比較,發(fā)現(xiàn)Zbar解碼比Zxing速度要快,實(shí)現(xiàn)方式也簡單,需要的朋友可以參考下2023-03-03