閱讀該文章前,可以先閱讀我前兩篇文章
微信自動回復(fù)和自動搶紅包實(shí)現(xiàn)原理(一):AccessibilityService的介紹和配置
微信自動回復(fù)和自動搶紅包實(shí)現(xiàn)原理(二):自動回復(fù)
經(jīng)過前兩篇文章的閱讀,我相信大家應(yīng)該對AccessibilityService有一定的了解了爵卒,是不是已經(jīng)按捺不住侠仇,想自己動手試試从隆?先別急歉眷,可以再看完我這篇文章還不遲崇决,相信你另有收獲的材诽。接下來我們來探索一下自動搶紅包的實(shí)現(xiàn)原理底挫。
看了我第二篇微信自動回復(fù)文章的朋友應(yīng)該知道怎么做了,只是一些操作上不同:
- 監(jiān)聽TYPE_NOTIFICATION_STATE_CHANGED事件
- 根據(jù)Notification打開會話人聊天界面
- 搜索紅包控件
- 點(diǎn)擊紅包控件脸侥,打開紅包建邓,如果紅包已被搶,跳至第6步湿痢,否則執(zhí)行第5步
- 點(diǎn)擊紅包界面的“開”按鈕涝缝,搶紅包
- 返回微信主界面
好吧扑庞,我們給測試手機(jī)微信發(fā)個紅包譬重,先打印log來看看,具體信息不貼了罐氨,直接看結(jié)果:
打開微信的界面
-------------------------------------------------------------
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
-------------------------------------------------------------
經(jīng)我測試臀规,LauncherUI只有微信在后臺才會觸發(fā),但微信在前臺時也會有Notification栅隐,所以有LuckyMoneyReceiveUI塔嬉、LuckyMoneyDetailUI兩個界面我們已經(jīng)足夠了
接下來的工作是找到相應(yīng)的控件了。先找紅包這個控件租悄,給測試機(jī)微信發(fā)多幾次紅包谨究,找到每個紅包的相同點(diǎn)。
看到紅色框框沒泣棋,“領(lǐng)取紅包”這個控件每次都不變了胶哲,可以根據(jù)其找到其父控件,再點(diǎn)擊就可以打開紅包了潭辈!
接下來就是紅包界面的“開”按鈕了鸯屿。很遺憾,因?yàn)樵摪粹o即每文本信息把敢,也沒特別的子控件寄摆,沒辦法,只能直接用控件的id了(但這種方法不好修赞,因?yàn)閾?jù)了解婶恼,控件的id經(jīng)常會變,可能就會了防止這類插件的出現(xiàn)吧柏副,哈哈)熙尉,下面介紹如何獲取控件的id。
1.打開DDMS搓扯,連接手機(jī)检痰,打開一個紅包,進(jìn)入紅包界面锨推,點(diǎn)擊下面按鈕
2.選中你需要的控件铅歼,例如這里我們是要查看“開”按鈕這控件
3.在右邊就可以查看控件的信息了公壤,右下方可以查看id
嗯,對的椎椰,紅包的控件也可以這樣獲取厦幅,但我說過了,id是會變的慨飘,所以能不用就最好不要用确憨。還有如果有朋友知道不用id獲取“開”按鈕的話,請告訴我一聲哈瓤的。
好了休弃,所有難點(diǎn)都解決了,接下來只要寫代碼處理下邏輯就好了圈膏,直接上代碼吧塔猾。
**
* 自動搶紅包服務(wù)
*/
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); // 喚醒點(diǎn)亮屏幕
}
openAppByNotification(event); // 打開微信
hasNotify = true;
break;
default:
Log.i(TAG, "DEFAULT");
if(hasNotify) {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
clickLuckyMoney(rootNode); // 點(diǎn)擊紅包
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();
}
}
}
/**
* 搜索并點(diǎn)擊紅包
*/
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("領(lǐng)取紅包")) {
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丈甸,到這里就全部講完了,小伙伴們可以自己去實(shí)現(xiàn)更多更有趣尿褪、更新奇的功能了睦擂。這里我只是作為技術(shù)探索,容我再啰嗦兩點(diǎn):
- 朋友是很重要的杖玲,有空的話還是好好回復(fù)吧
- 紅包只是一種噱頭顿仇,一種娛樂方式,別當(dāng)作謀財之道喔