- 搶紅包插件
先回顧一下搶紅包的的流程:
- 狀态欄出現"[微信紅包]"的消息提示,點選進入聊天界面
- 點選相應的紅包資訊,彈出搶紅包界面
- 在搶紅包界面點選"開",打開紅包
- 在紅包詳情頁面,檢視詳情,點選傳回按鈕傳回微信聊天界面.
以上是不在微信聊天界面時的流程.如果你所在的微信聊天視窗出現紅包,則不會執行步驟1,而是直接執行2,3,4.如果是在微信好友清單時,收到紅包,則會在清單項中顯示[微信紅包],需要點即該清單項,進入聊天界面,随後執行2,3,4.為了友善示範,這裡我們暫時不考慮好友清單時出現紅包的情況.
明白了搶紅包流程,之後我們通過AccessibilityService擷取通知欄資訊及微信聊天視窗界面,繼而通過模拟點選實作打開紅包,搶紅包等操作.
AccessibilityService配置如下:
<?xml version="1.0" encoding="utf-8"?>
<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:notificationTimeout="100"
android:packageNames="com.tencent.mm" />
具體實作代碼如下:
public class RobService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
handleNotification(event);
break;
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
String className = event.getClassName().toString();
if (className.equals("com.tencent.mm.ui.LauncherUI")) {
getPacket();
} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) {
openPacket();
} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) {
close();
}
break;
}
}
/**
* 處理通知欄資訊
*
* 如果是微信紅包的提示資訊,則模拟點選
*
* @param event
*/
private void handleNotification(AccessibilityEvent event) {
List<CharSequence> texts = event.getText();
if (!texts.isEmpty()) {
for (CharSequence text : texts) {
String content = text.toString();
//如果微信紅包的提示資訊,則模拟點選進入相應的聊天視窗
if (content.contains("[微信紅包]")) {
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_MR2)
private void close() {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
//為了示範,直接檢視了關閉按鈕的id
List<AccessibilityNodeInfo> infos = nodeInfo.findAccessibilityNodeInfosByViewId("@id/ez");
nodeInfo.recycle();
for (AccessibilityNodeInfo item : infos) {
item.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
/**
* 模拟點選,拆開紅包
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void openPacket() {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
//為了示範,直接檢視了紅包控件的id
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("@id/b9m");
nodeInfo.recycle();
for (AccessibilityNodeInfo item : list) {
item.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
/**
* 模拟點選,打開搶紅包界面
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void getPacket() {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
AccessibilityNodeInfo node = recycle(rootNode);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
AccessibilityNodeInfo parent = node.getParent();
while (parent != null) {
if (parent.isClickable()) {
parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
break;
}
parent = parent.getParent();
}
}
/**
* 遞歸查找目前聊天視窗中的紅包資訊
*
* 聊天視窗中的紅包都存在"領取紅包"一詞,是以可根據該詞查找紅包
*
* @param node
*/
public AccessibilityNodeInfo recycle(AccessibilityNodeInfo node) {
if (node.getChildCount() == 0) {
if (node.getText() != null) {
if ("領取紅包".equals(node.getText().toString())) {
return node;
}
}
} else {
for (int i = 0; i < node.getChildCount(); i++) {
if (node.getChild(i) != null) {
recycle(node.getChild(i));
}
}
}
return node;
}
@Override
public void onInterrupt() {
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
}
}
上面的代碼簡單示範了搶紅包的原理,為了友善起見,我直接通過
findAccessibilityNodeInfosByViewId()
擷取制定id控件.在實際中,這種方法不太可靠,到目前為止,微信已經改過幾次相關控件的id了.
有童鞋問,怎麼樣知道該控件的id呢.其實很簡單,android中已經為我們提供了相關的工具:在Android Studio中開啟Android Device Monitor,選擇裝置後點選Dump View Hierarchy for UI Automator,如下:
這裡寫圖檔描述
稍等片刻之後,便會出現目前裝置的視窗,在該視窗中點選相關控件,便會顯示該控件的屬性.借助該工具,可以幫我們快速的分析界面結構,幫助我們從其他app布局政策中學習
這裡寫圖檔描述
我們用Dump View Hierarchy for UI Automator分析聊天界面微信紅包資訊:
這裡寫圖檔描述
搶紅包界面:
這裡寫圖檔描述