微信自動回覆和自動搶紅包實現原理(三):自動搶紅包
經過前兩篇文章的閱讀,我相信大家應該對AccessibilityService有一定的瞭解了,是不是已經按捺不住,想自己動手試試?先別急,可以再看完我這篇文章還不遲,相信你另有收穫的。接下來我們來探索一下自動搶紅包的實現原理。
看了我第二篇微信自動回覆文章的朋友應該知道怎麼做了,只是一些操作上不同:
1. 監聽TYPE_NOTIFICATION_STATE_CHANGED事件
2. 根據Notification開啟會話人聊天介面
3. 搜尋紅包控制元件
4. 點選紅包控制元件,開啟紅包,如果紅包已被搶,跳至第6步,否則執行第5步
5. 點選紅包介面的“開”按鈕,搶紅包
6. 返回微信主介面
好吧,我們給測試手機微信發個紅包,先列印log來看看,具體資訊不貼了,直接看結果:
開啟微信的介面
-------------------------------------------------------------
PackageName:com.tencent.mm
Source Class:com.tencent.mm.ui.LauncherUI
Description:null
Event Type(int):32
-------------------------------------------------------------
紅包接收介面(不管紅包還沒搶光還是已被搶光都會開啟這個介面)
-------------------------------------------------------------
PackageName:com.tencent.mm
Source Class:com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI
Description:null
Event Type(int):32
-------------------------------------------------------------
紅包詳情介面(也就是搶到紅包以後的介面)
-------------------------------------------------------------
PackageName:com.tencent.mm
Source Class:com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI
Description:null
Event Type(int):32
-------------------------------------------------------------
經我測試,LauncherUI只有微信在後臺才會觸發,但微信在前臺時也會有Notification,所以有LuckyMoneyReceiveUI、LuckyMoneyDetailUI兩個介面我們已經足夠了
接下來的工作是找到相應的控制元件了。先找紅包這個控制元件,給測試機微信發多幾次紅包,找到每個紅包的相同點。
看到紅色框框沒,“領取紅包”這個控制元件每次都不變了,可以根據其找到其父控制元件,再點選就可以開啟紅包了!
接下來就是紅包介面的“開”按鈕了。很遺憾,因為該按鈕即每文字資訊,也沒特別的子控制元件,沒辦法,只能直接用控制元件的id了(但這種方法不好,因為據瞭解,控制元件的id經常會變,可能就會了防止這類外掛的出現吧,哈哈),下面介紹如何獲取控制元件的id。
1.開啟DDMS,連線手機,開啟一個紅包,進入紅包介面,點選下面按鈕
2.選中你需要的控制元件,例如這裡我們是要檢視“開”按鈕這控制元件
3.在右邊就可以檢視控制元件的資訊了,右下方可以檢視id
嗯,對的,紅包的控制元件也可以這樣獲取,但我說過了,id是會變的,所以能不用就最好不要用。還有如果有朋友知道不用id獲取“開”按鈕的話,請告訴我一聲哈。
好了,所有難點都解決了,接下來只要寫程式碼處理下邏輯就好了,直接上程式碼吧。
**
* 自動搶紅包服務
*/
public class AutoOpenLuckyMoneyService extends AccessibilityService{
private static final String TAG = AutoOpenLuckyMoneyService.class.getSimpleName();
private static final int MSG_BACK_HOME = 0;
private static final int MSG_BACK_ONCE = 1;
boolean hasNotify = false;
boolean hasLuckyMoney = true;
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType(); // 事件型別
switch (eventType) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: // 通知欄事件
Log.i(TAG, "TYPE_NOTIFICATION_STATE_CHANGED");
if(PhoneController.isLockScreen(this)) { // 鎖屏
PhoneController.wakeAndUnlockScreen(this); // 喚醒點亮螢幕
}
openAppByNotification(event); // 開啟微信
hasNotify = true;
break;
default:
Log.i(TAG, "DEFAULT");
if(hasNotify) {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
clickLuckyMoney(rootNode); // 點選紅包
String className = event.getClassName().toString();
if (className.equals(UI.LUCKY_MONEY_RECEIVE_UI)) { //紅包接收介面
if(!openLuckyMoney()) { // 如果紅包被搶光了,就返回主介面
backToHome();
hasNotify = false;
}
hasLuckyMoney = true;
} else if (className.equals(UI.LUCKY_MONEY_DETAIL_UI)) { // 搶到紅包
backToHome();
hasNotify = false;
hasLuckyMoney = true;
} else { // 處理沒紅包的情況,直接返回主介面
if(!hasLuckyMoney) {
handler.sendEmptyMessage(MSG_BACK_ONCE);
hasLuckyMoney = true; // 防止後退多次
}
}
}
break;
}
}
@Override
public void onInterrupt() {
}
/**
* 開啟微信
* @param event 事件
*/
private void openAppByNotification(AccessibilityEvent event) {
if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
Notification notification = (Notification) event.getParcelableData();
try {
PendingIntent pendingIntent = notification.contentIntent;
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}
/**
* 搜尋並點選紅包
*/
private void clickLuckyMoney(AccessibilityNodeInfo rootNode) {
if(rootNode != null) {
int count = rootNode.getChildCount();
for (int i = count - 1; i >= 0; i--) { // 倒序查詢最新的紅包
AccessibilityNodeInfo node = rootNode.getChild(i);
if (node == null)
continue;
CharSequence text = node.getText();
if (text != null && text.toString().equals("領取紅包")) {
AccessibilityNodeInfo parent = node.getParent();
while (parent != null) {
if (parent.isClickable()) {
parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
break;
}
parent = parent.getParent();
}
}
clickLuckyMoney(node);
}
}
}
/**
* 開啟紅包
*/
private boolean openLuckyMoney() {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
if(rootNode != null) {
List<AccessibilityNodeInfo> nodes =
rootNode.findAccessibilityNodeInfosByViewId(UI.OPEN_LUCKY_MONEY_BUTTON_ID);
for(AccessibilityNodeInfo node : nodes) {
if(node.isClickable()) {
Log.i(TAG, "open LuckyMoney");
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
return true;
}
}
}
return false;
}
private void backToHome() {
if(handler.hasMessages(MSG_BACK_HOME)) {
handler.removeMessages(MSG_BACK_HOME);
}
handler.sendEmptyMessage(MSG_BACK_HOME);
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == MSG_BACK_HOME) {
performGlobalAction(GLOBAL_ACTION_BACK);
postDelayed(new Runnable() {
@Override
public void run() {
performGlobalAction(GLOBAL_ACTION_BACK);
hasLuckyMoney = false;
}
}, 1500);
} else if(msg.what == MSG_BACK_ONCE) {
postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "click back");
performGlobalAction(GLOBAL_ACTION_BACK);
hasLuckyMoney = false;
hasNotify = false;
}
}, 1500);
}
}
};
}
ok,到這裡就全部講完了,小夥伴們可以自己去實現更多更有趣、更新奇的功能了。這裡我只是作為技術探索,容我再囉嗦兩點:
1. 朋友是很重要的,有空的話還是好好回覆吧
2. 紅包只是一種噱頭,一種娛樂方式,別當作謀財之道喔