关闭

Android之微信抢红包实现原理分析

1593人阅读 评论(1) 收藏 举报
分类:

微信抢红包主要用到AccessibilityService,该服务需要用户手动到辅助功能里面授权,下面直接粘贴源码,先看Activity,主要是跳转到辅助功能界面,让用户开启辅助功能的服务:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        View btn = findViewById(R.id.open_help_btn);
        btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(
                        android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
                startActivity(intent);
            }
        });
    }

}

下面看服务的使用,需要配置相关参数,如:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_description"
    android:notificationTimeout="100"
    android:packageNames="com.tencent.mm" />

再看服务的声明:

<service
    android:name="com.yongfei.hongbao.AccService"
    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/service_config" />
</service>

最后看抢红包功能的实现:

public class AccService extends AccessibilityService {

    private static final String NOTIFICATION_HONGBAO = "[微信红包]";
    private static final String HONGBAO_MSG = "微信红包";
    private static final String LAUNCHER_UI = "com.tencent.mm.ui.LauncherUI";
    private static final String OPEN_MONEY_UI = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI";
    private static final String OPEN_ID = "com.tencent.mm:id/ba_";
    private boolean mIsFromNotification = false;
    // 标记在微信主界面时收到红包消息
    private boolean mIsMsgWindow = true;
    private WakeLock mWakeLock;
    private KeyguardManager mKeyguardManager;
    private KeyguardLock mKeyguardLock;
    private boolean mIsOperationLock = false;

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        int eventType = event.getEventType();
        if (eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
            List<CharSequence> text = event.getText();
            if (!text.isEmpty()) {
                for (CharSequence item : text) {
                    String t = String.valueOf(item);
                    System.out.println("zyf通知内容:" + t);
                    if (t.contains(NOTIFICATION_HONGBAO)) {
                        mIsFromNotification = true;
                        mIsMsgWindow = true;
                        if (isKeyguardLocked()) {
                            wakeAndUnlock(true);
                        }
                        openNotification(event);
                        break;
                    }
                }
            }
        } else if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            mIsMsgWindow = false;
            // 只有从通知栏进入聊天界面的才点击红包消息/拆红包
            // 因为拆完红包返回时也会引起窗口变化
            if (mIsFromNotification) {
                windowStateChanged(event);
                return;
            }
            // 聊天界面手动点击红包消息时,自动拆包
            if (OPEN_MONEY_UI.equals(event.getClassName())) {
                // 拆红包界面,点击拆红包
                openHongBao();
            }
        }
    }

    private void wakeAndUnlock(boolean unlock) {
        if (unlock) {
            PowerManager manager = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = manager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
                    | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "money");
            mWakeLock.acquire();
            if (mKeyguardManager != null) {
                mKeyguardLock = mKeyguardManager.newKeyguardLock("unLock");
                mKeyguardLock.disableKeyguard();
                mIsOperationLock = true;
            }
        } else {
            if (mKeyguardLock != null) {
                mKeyguardLock.reenableKeyguard();
                mIsOperationLock = false;
            }
            if (mWakeLock != null) {
                mWakeLock.release();
            }
        }
    }

    private boolean isKeyguardLocked() {
        mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        return mKeyguardManager.isKeyguardLocked();
    }

    /**
     * 界面变化
     * 
     * @param event
     */
    private void windowStateChanged(AccessibilityEvent event) {
        if (LAUNCHER_UI.equals(event.getClassName())) {
            // 主界面或聊天界面,点击红包消息
            clickHongBaoMsg();
        } else if (OPEN_MONEY_UI.equals(event.getClassName())) {
            // 拆红包界面,点击拆红包
            openHongBao();
        }
    }

    /**
     * 拆红包
     */
    private void openHongBao() {
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if (nodeInfo == null) {
            System.out.println("zyf openHongBao is null");
            return;
        }
        // 抢别人发的红包
        List<AccessibilityNodeInfo> openId = nodeInfo
                .findAccessibilityNodeInfosByViewId(OPEN_ID);
        if (openId != null && openId.size() > 0) {
            openId.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
        }if (mIsOperationLock) { wakeAndUnlock(false); }
        // 抢没抢到红包都要把变量赋为false,以便后续继续拆从通知栏进来的红包消息
        mIsFromNotification = false;

    }

    /**
     * 点击红包消息
     */
    private void clickHongBaoMsg() {
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if (nodeInfo == null) {
            System.out.println("zyf rootwindow is null");
            return;
        }
        List<AccessibilityNodeInfo> list = nodeInfo
                .findAccessibilityNodeInfosByText(HONGBAO_MSG);
        if (list.size() >= 1) {
            // 只拆最后一个红包
            AccessibilityNodeInfo item = list.get(list.size() - 1);
            AccessibilityNodeInfo parent = item.getParent();
            parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
        }
    }

    /**
     * 打开通知栏消息
     * 
     * @param event
     */
    private void openNotification(AccessibilityEvent event) {
        if (event.getParcelableData() == null
                || !(event.getParcelableData() instanceof Notification)) {
            return;
        }

        // 获取通知栏的意图并打开
        Notification notification = (Notification) event.getParcelableData();
        PendingIntent pendingIntent = notification.contentIntent;
        try {
            pendingIntent.send();
            // 只有接收到通知并且窗口没有变化时才需要点击红包消息
            // 因为此时是在微信主界面
            if (mIsMsgWindow) {
                clickHongBaoMsg();
            }
        } catch (CanceledException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onInterrupt() {
        System.out.println("zyf 服务中断了");
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        System.out.println("zyf 服务连接成功");
    }

}

由于上面用到wakelock和解锁/锁屏功能,故需要在配置文件中添加相关权限:

<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>

另外,需要把apk加入到各种白名单,因为应用被杀后辅助功能会自动收回该应用的授权。

另外,手机静音时该服务是不可用的。

附apk下载链接

上面代码是基于微信6.3.23版本实现的,不同版本id可能会不同。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:118569次
    • 积分:2946
    • 等级:
    • 排名:第11994名
    • 原创:174篇
    • 转载:51篇
    • 译文:0篇
    • 评论:126条
    文章分类
    最新评论