微信抢红包,基于AccessibilityService,微信6.6.1亲测有效

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tingfengzheshuo/article/details/79146860

前段时间突然对抢红包原理感兴趣,网上找了些相关资料,但是网上资料同质化严重,也只能做参考了,自己上手后还填了一些坑


原理

基于AccessibilityService服务类,这个类的使用网上资料很多,我就不详说了。后台监听微信,如果发现被唤醒,就检查通知,如果是红包通知就转入微信。

show u my code


package nodec.bsssss.com.grabredpacketc.Service;

import android.accessibilityservice.AccessibilityService;
import android.app.Notification;
import android.app.PendingIntent;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;


/**
 * Created by shijg on 2018/1/4.
 */

public class GrabService extends AccessibilityService {
    private static final String TAG = "Plus";
    private static final String FLOW = "flow";

    private int serviceState = -1;

    private static final int FLAG_BACKGROUND = 100;
    private static final int FLAG_CHAT_LIST = 200;
    private static final int FLAG_CHAT_DETAIL = 300;
    private static final int FLAG_PACKET_RECEIVE = 500;
    private static final int FLAG_PACKET_DETAIL = 600;
    private static final int FLAG_IGNORE = 400;

    private int behavior = -1;

    private static final int FLAG_CAUGHT = 500;
    private static final int FLAG_FOUND = 900;
    private static final int FLAG_OPENING = 600;
    private static final int FLAG_OPENED = 700;
    private static final int FLAG_INS = 800;

    private Timer timer = null;

    private int start = -1;

    private static final int START_BACKGROUND = 100;
    private static final int START_LIST = 200;
    private static final int START_DETAIL = 300;

    private boolean back = false;

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        int eventType = event.getEventType();
        String className = event.getClassName().toString();
        if (back)return;
        switch (eventType) {
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 监听微信通知
                handleNotification(event);
                break;
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                if (start == START_BACKGROUND && serviceState == FLAG_BACKGROUND && behavior == FLAG_FOUND){// 兼容一些设备
                    AccessibilityNodeInfo node = getPacket();
                    while (node != null){
                        if (node.isClickable()){
                            serviceState = FLAG_CHAT_DETAIL;
                            start = START_BACKGROUND;// 从后台唤醒标识
                            behavior = FLAG_CAUGHT;
                            node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            break;
                        }
                        node = node.getParent();
                    }
                    return;
                }
                // 拆开红包界面
                if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(className)){
//                    findATarget = 0;
                    // TODO
                    timer = new Timer(true);
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            openPacket(getRootInActiveWindow());
                            behavior = FLAG_OPENED;
                            serviceState = FLAG_PACKET_DETAIL;
                        }
                    },300);
                    return;
                }
                // 红包详情界面
//                if (serviceState == FLAG_PACKET_DETAIL && behavior == FLAG_OPENED && "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(className) ){
                if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(className) ){
                    close(getRootInActiveWindow());
                    back = true;
                    serviceState = FLAG_CHAT_DETAIL;
                    behavior = FLAG_INS;
                    if (start == START_BACKGROUND || start == START_LIST){
                        timer = new Timer(true);
                        timer.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                close(getRootInActiveWindow());
                                serviceState = FLAG_CHAT_LIST;
                                back = false;
                                timer.cancel();
                            }
                        },400);
                    }else {
                        back = false;
                    }
                    return;
                }
                break;

            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                // 未发现红包时监听聊天列表
                if (behavior == FLAG_INS && className.equals("android.widget.ImageView")){
//                if (serviceState == FLAG_CHAT_LIST && behavior == FLAG_INS && className.equals("android.widget.ImageView")){
                    AccessibilityNodeInfo node = recycleContains(getRootInActiveWindow());
                    if(node != null){
                        while (node != null){
                            if (node.isClickable()){
                                serviceState = FLAG_CHAT_DETAIL;
                                start = START_LIST;
                                behavior = FLAG_FOUND;
                                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                                break;
                            }
                            node = node.getParent();
                        }
                        return;
                    }else {
                        // 监听聊天详情页面
                        AccessibilityNodeInfo node1 = getPacket();
                        while (node1 != null){
                            if (node1.isClickable()){
                                serviceState = FLAG_CHAT_DETAIL;
                                start = START_DETAIL;
                                behavior = FLAG_FOUND;
                                node1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                                break;
                            }
                            node1 = node1.getParent();
                        }
                        return;
                    }

                }
//                // 打开在列表中发现的红包
                if (serviceState == FLAG_CHAT_DETAIL && start == START_LIST && className.equals("android.widget.ImageView") && behavior == FLAG_FOUND){
                    AccessibilityNodeInfo node = getPacket();
                    while (node != null){
                        if (node.isClickable()){
                            serviceState = FLAG_CHAT_DETAIL;
                            start = START_LIST;
                            behavior = FLAG_CAUGHT;
                            node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            break;
                        }
                        node = node.getParent();
                    }
                    return;
                }
                break;
        }
    }

    @Override
    public void onInterrupt() {

    }

    public 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 {
                            behavior = FLAG_FOUND;
                            serviceState = FLAG_BACKGROUND;
                            start = START_BACKGROUND;
                            pendingIntent.send();
                        } catch (PendingIntent.CanceledException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Toast.makeText(getApplicationContext(),"服务成功开启",Toast.LENGTH_SHORT).show();
    }

    private void close(AccessibilityNodeInfo rootNode) {
        AccessibilityNodeInfo closeNode = getCloseNode(rootNode);
        if (closeNode != null) {
            closeNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            closeNode.recycle();
        }
    }

    /**
     * 模拟点击,拆开红包
     */
    private void openPacket(AccessibilityNodeInfo nodeInfo) {
        if (nodeInfo != null) {
            AccessibilityNodeInfo node = getOpenButton(nodeInfo);
            if (node != null){
                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                node.recycle();
            }
            nodeInfo.recycle();
        }
    }

    private AccessibilityNodeInfo getPacket() {
        AccessibilityNodeInfo rootNode = getRootInActiveWindow();
        return recycle(rootNode,"领取红包");
    }

    private boolean checkPacketFromList(AccessibilityNodeInfo rootNode){
        Log.d(TAG,"checkPacketFromList");

        return false;
    }

    public AccessibilityNodeInfo recycleContains(AccessibilityNodeInfo node){
        if (node.getChildCount() == 0){
            if (node.getText() != null){
                if (node.getText().toString().contains("[微信红包]")){
                    return node;
                }
            }
        }else {
            for (int i = 0; i < node.getChildCount(); i++) {
                if (node.getChild(i) != null) {
                    AccessibilityNodeInfo agent = recycleContains(node.getChild(i));
                    if (agent != null)return agent;
                }
            }
        }
        return null;
    }

    public AccessibilityNodeInfo recycle(AccessibilityNodeInfo node,String text) {
        if (node.getChildCount() == 0) {
            if (node.getText() != null) {
                if (text.equals(node.getText().toString())) {
                    return node;
                }
            }
        } else {
            for (int i = node.getChildCount() - 1; i > -1; i--) {
                if (node.getChild(i) != null) {
                    AccessibilityNodeInfo agent = recycle(node.getChild(i),text);
                    if (agent != null)return agent;
                }
            }
        }
        return null;
    }

    private AccessibilityNodeInfo getOpenButton(AccessibilityNodeInfo node){
        if (node.getChildCount() == 0) {
            if ("android.widget.Button".equals(node.getClassName().toString())) {
                if (node.getText() != null)Log.d(FLOW,node.getText().toString());
                return node;
            }
        } else {
            for (int i = 0; i < node.getChildCount(); i++) {
                if (node.getChild(i) != null) {
                    AccessibilityNodeInfo agent = getOpenButton(node.getChild(i));
                    if (agent != null)return agent;
                }
            }
        }
        return null;
    }

    private AccessibilityNodeInfo getCloseNode(AccessibilityNodeInfo node){
        if (node.getChildCount() > 0){
            if ("android.widget.LinearLayout".equals(node.getClassName().toString()) && node.isClickable() && hasImageViewChild(node)){
                return node;
            }else {
                for (int i = 0; i < node.getChildCount(); i++) {
                    AccessibilityNodeInfo agent = getCloseNode(node.getChild(i));
                    if (agent != null)return agent;
                }
            }
        }
        return null;
    }
    private boolean hasImageViewChild(AccessibilityNodeInfo node){
        return node.getChildCount() > 0 && "android.widget.ImageView".equals(node.getChild(0).getClassName().toString());
    }
}
注册服务类
<?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="flagRetrieveInteractiveWindows|flagIncludeNotImportantViews"
    android:canRetrieveWindowContent="true"
    android:notificationTimeout="100"
    android:packageNames="com.tencent.mm" />

代码分析

抢红包可以分为三种场景,

1,微信在后台时

2,在微信聊天列表时

3,在微信聊天详情时


1

微信在后台时,收到红包会通知,来通知会收到
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
类型的window状态变更,拿到通知文本,如果包含微信红包字样就认为是有红包,转入微信(这有个坑,就是如果有人发文字‘微信红包’而不是真的发红包也会跳进去)

然后检测view树,找到红包,点击

2
3

2,3放在一起说是因为我一起处理了,微信如果有红包存在展示的其实是一张图片,所以我监听了className为android.widget.ImageView的AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED的类型通知



具体代码不多说了,量不多,自己看看就明白了,说说坑

网上很多代码是说在注册AccessibilityService时,把accessibilityFlags设为flagDefault,这会导致无法监听到一些窗口变化
,我设置为
flagRetrieveInteractiveWindows|flagIncludeNotImportantViews

有时窗口会发生捕获不到目标View的情况,所以延迟了一点时间再捕获

服务类的accessibilityEventType设为feedbackGeneric有时会导致获取根rootView为null,我设置为
typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged
写的时候还有一些其它的坑,现在想不起来了
github项目地址



猜你喜欢

转载自blog.csdn.net/tingfengzheshuo/article/details/79146860
今日推荐