教你一步步實(shí)現(xiàn)Android微信自動(dòng)搶紅包
本文介紹微信自動(dòng)搶紅包的實(shí)現(xiàn)方法,主要實(shí)現(xiàn)以下幾個(gè)功能:
1.自動(dòng)拆開(kāi)屏幕上出現(xiàn)的紅包
2.處于桌面或聊天列表時(shí)接收到紅包信息時(shí)自動(dòng)進(jìn)入聊天界面并拆紅包
3.日志功能,記錄搶紅包的詳細(xì)日志
實(shí)現(xiàn)原理
1.利用AccessibilityService輔助服務(wù),監(jiān)測(cè)屏幕內(nèi)容,實(shí)現(xiàn)自動(dòng)拆紅包的目的。
2.利用ActiveAndroid數(shù)據(jù)庫(kù)簡(jiǎn)單記錄紅包日志
3.利用preference實(shí)現(xiàn)監(jiān)控選項(xiàng)紀(jì)錄
最終界面

搶紅包核心代碼
AccessibilityService配置
android:accessibilityEventTypes 設(shè)置觸發(fā)監(jiān)聽(tīng)回調(diào)的事件類型;
android:packageNames 設(shè)置監(jiān)聽(tīng)的應(yīng)用,這里監(jiān)聽(tīng)的是微信,因此填上微信的包名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ā)送來(lái)的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 = "已存入零錢(qián)";
private static final String RED_PACKET_NOTIFICATION = "[微信紅包]";
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
L.d("RECEIVE EVENT!");
if (watchedFlags == null) return;
/* 檢測(cè)通知消息 */
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)接收到紅包并且還沒(méi)有戳開(kāi) */
if (mLuckyMoneyReceived && !mLuckyMoneyPicked && (mReceiveNode != null)) {
mMutex = true;
AccessibilityNodeInfo cellNode = mReceiveNode;
cellNode.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
mLuckyMoneyReceived = false;
mLuckyMoneyPicked = true;
L.d("正在打開(kāi)!");
}
/* 如果戳開(kāi)但還未領(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;
}
}
}
檢測(cè)監(jiān)聽(tīng)事件的節(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 {
/* 戳開(kāi)紅包,紅包還沒(méi)搶完,遍歷節(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;
}
}
/* 戳開(kāi)紅包,紅包已被搶完,遍歷節(jié)點(diǎn)匹配“已存入零錢(qiá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;
}
}
}
主要通過(guò)檢測(cè)“領(lǐng)取紅包”等關(guān)鍵文字信息來(lái)判斷是否有新紅包
檢測(cè)收到紅包時(shí)判斷是否"android.widget.LinearLayout",屏蔽聊天信息中的文字干擾
拆紅包時(shí),由于微信版本可能不同,同時(shí)進(jìn)行兩種判斷,以兼容部分版本
拆完紅包需自動(dòng)返回,有以下幾種情況:搶到了,手慢了,以及該紅包是自己發(fā)出的紅包
下面是監(jiān)聽(tīng)聊天列表的代碼:
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)聽(tīng)通知信息的代碼:
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ǔ)
通過(guò)獲取節(jié)點(diǎn)的子信息,分別獲得紅包發(fā)送者及搶到的金額、搶紅包時(shí)間等信息,建立簡(jiǎn)單的表單分別記錄該信息。
@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é)束,目前在微信最新版上測(cè)試ok,尚還存在以下幾個(gè)問(wèn)題:
1.同一個(gè)人連續(xù)發(fā)的不能自動(dòng)搶,因?yàn)闉榱朔乐怪貜?fù)點(diǎn)擊做了過(guò)濾,同一個(gè)人的紅包搶了后不會(huì)再次點(diǎn)擊
2.AccessibilityService開(kāi)啟時(shí)間長(zhǎng)后有時(shí)會(huì)被系統(tǒng)關(guān)掉
結(jié)束語(yǔ)
以上就是本文的全部?jī)?nèi)容了,希望對(duì)大家的學(xué)習(xí)和工作能有所幫助。
- java模擬微信搶紅包的實(shí)例代碼
- IOS 實(shí)現(xiàn)微信自動(dòng)搶紅包(非越獄IPhone)
- 詳解利用redis + lua解決搶紅包高并發(fā)的問(wèn)題
- js仿微信搶紅包功能
- laravel框架實(shí)現(xiàn)后臺(tái)登錄、退出功能示例
- Laravel框架實(shí)現(xiàn)即點(diǎn)即改功能的方法分析
- laravel 實(shí)現(xiàn)用戶登錄注銷(xiāo)并限制功能
- 利用laravel+ajax實(shí)現(xiàn)文件上傳功能方法示例
- laravel框架關(guān)于搜索功能的實(shí)現(xiàn)
- Laravel框架實(shí)現(xiàn)利用中間件進(jìn)行操作日志記錄功能
- Laravel框架實(shí)現(xiàn)搶紅包功能示例
相關(guān)文章
Android 對(duì)話框(Dialog)大全詳解及示例代碼
本文主要介紹Android 對(duì)話框的知識(shí),這里整理了詳細(xì)資料及實(shí)現(xiàn)示例代碼及實(shí)現(xiàn)效果圖,有興趣的小伙伴可以參考下2016-09-09
Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實(shí)現(xiàn)
這篇文章主要介紹了Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Android中HttpURLConnection類使用介紹
早些時(shí)候其實(shí)我們都習(xí)慣性使用HttpClient,但是后來(lái)Android6.0之后不再支持HttpClient,需要添加Apache的jar才行,所以,就有很多開(kāi)發(fā)者放棄使用HttpClient了,HttpURLConnection畢竟是標(biāo)準(zhǔn)Java接口(java.net) ,適配性還是很強(qiáng)的2022-12-12
Android實(shí)現(xiàn)界面左右滑動(dòng)切換功能
相信大家一定都使用過(guò)手機(jī)QQ和微信之類的軟件,當(dāng)我們使用時(shí)不難發(fā)現(xiàn)其界面的切換不僅可以通過(guò)點(diǎn)擊頁(yè)標(biāo)簽來(lái)實(shí)現(xiàn),還可以通過(guò)左右滑動(dòng)來(lái)實(shí)現(xiàn)的,下面小編給大家介紹下如何實(shí)現(xiàn)這個(gè)功能2016-12-12
Android 使用Zbar實(shí)現(xiàn)掃一掃功能
這篇文章主要介紹了Android 使用Zbar實(shí)現(xiàn)掃一掃功能,本文用的是Zbar實(shí)現(xiàn)掃一掃,因?yàn)楦鶕?jù)本人對(duì)兩個(gè)庫(kù)的使用比較,發(fā)現(xiàn)Zbar解碼比Zxing速度要快,實(shí)現(xiàn)方式也簡(jiǎn)單,需要的朋友可以參考下2023-03-03

