一步一步实现微信抢红包

  圣诞过后,又到了抢红包的季节。各个公司的年会将逐渐展开,各个红包群就热闹了起来。为了应对领导在群里时不时的一个红包,写一个抢红包的应用迫在眉睫了。之前由于没有自动抢红包错失了100RMB+的红包啊!
  先来整理下思路。要实现抢红包,那么就要在红包来的时候去打开微信,执行点击的动作。被点击的控件肯定是带有红包关键字的。打开红包后,还需要去点击一下打开。
  为了实现上面的一系列步骤,方法有两种。
第一从framwork进行修改。这种方式适合于自制rom。如手机厂商多采用这种方法。有个同事就通过这方法实现了红包功能。
第二就只能通过google 提供了一个辅助服务类了。该类可以监听通知、监听窗口变化,模拟点击等功能。该文就采用辅助服务类。

STEP1 辅助服务类的使用。

通过配置manifest文件就可以使用辅助服务了。

        <service
            android:name=".RedService"
            android:enabled="true"
            android:exported="true"
            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/red_service_config" />
        </service>

该服务可以进行配置,配置如下:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged"//监听类型 消息通知和窗口变化
    android:accessibilityFeedbackType="feedbackGeneric"//反馈方式
    android:accessibilityFlags=""
    android:canRetrieveWindowContent="true"//是否允许我们的程序读取窗口中的节点和内容
    android:description="@string/accessibility_description"
    android:notificationTimeout="100"
    android:packageNames="com.tencent.mm" />//监听的包名

配置好后,该服务就可以使用了。可以通过一个按钮引导用户去开启这个服务

 Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
                startActivity(intent);
                Log.d(TAG,"打开系统设置");

因为这个服务在系统设置里,所以通过点击去打开系统设置。然后就可以开启次服务。
接下来就是重点了。
首先需要去继承一个AccessibilityService 。

public class RedService extends AccessibilityService {

    public void onAccessibilityEvent(AccessibilityEvent event){
    ......
    }
    public void onInterrupt() {

    }
}

需要去重写他的两个方法。onAccessibilityEvent方法用来接收服务监听的事件,此处为通知和窗口变化。
现在先来看看 通知来的时候如何处理:

public void onAccessibilityEvent(AccessibilityEvent event){
        final int eventType = event.getEventType();
        Log.d(TAG,"event = "+event);
        //notifycation
        if (eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {// 监听到通知
            List<CharSequence> texts = event.getText();

            //解析通知内容
            if (!texts.isEmpty()) {
                for (CharSequence t : texts) {
                //如果有WECHAT_KEYNAME = "[微信红包]"
                    if (text.contains(WECHAT_KEYNAME)) {
                        if(!isopen) {
                        //根据通知打开应用
                            openNotification(event);
                            setOpenredbagState(true);
                        }

                        break;
                    }
                }
            }
        }
 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();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
        }
    }

在打开微信后,会发生窗口状态变化。这个时候该事件将会被监听。
此处要说的是微信的聊天界面和聊天列表的界面其实是在一个activity。都为
com.tencent.mm.ui.LauncherUI。
而且聊天界面是整个Activity contentView的父VIEW。通过解析页面可以轻易的发现。
再新打开的页面上,通过辅助类提供的方法对节点进行遍历。

private void clickRedBag() {

        //获取跟节点
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if (nodeInfo == null) {
            Log.w(TAG, "rootWindow为空");
            return;
        }
        //获取该节点下有 领取红包 关键字的节点
        List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("领取红包");
        if (list.isEmpty()) {
            list = nodeInfo.findAccessibilityNodeInfosByText(WECHAT_KEYNAME);
            for (AccessibilityNodeInfo n : list) {
                Log.i(TAG, "-->微信红包:" + n);
                n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                break;
            }
        } else {
            //点击红包
            for (int i = list.size() - 1; i >= 0; i--) {
                AccessibilityNodeInfo parent = list.get(i).getParent();
                Log.i(TAG, "-->点击红包:" + parent);
                if (parent != null) {
                    parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                    break;
                }
            }
        }
    }

通过 AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); 获取跟节点,同时也可以通过getchirld 方法来看看他的子节点。打印如下:

nodeInfo = android.view.accessibility.AccessibilityNodeInfo@8000744e;   packageName: com.tencent.mm; className: android.widget.FrameLayout; text: null; error: null; maxTextLength: -1; contentDescription: 当前所在页面,与走向通往康庄的大道上(4)的聊天; 

nodeInfo.getChild(i) = android.view.accessibility.AccessibilityNodeInfo@8000780f; boundsInParent: Rect(0, 0 - 1080, 1398); boundsInScreen: Rect(0, 216 - 1080, 1614); packageName: com.tencent.mm; className: com.tencent.mm.ui.mogic.WxViewPager; 

......

在android.widget.FrameLayout 下一共有8个子Node,不一一列举。上面列举了一个叫com.tencent.mm.ui.mogic.WxViewPager的view这个view 就是我们的聊天列表。
其余7个分别是搜索、更多、微信、通信录等。
 &emsp;当我们在聊天页面点击红包后,会弹出一个为打开的红包或者可能提示红包已到期。重点说说正常情况下红弹出红包的情况。弹出红包将会触发一个event,该event为窗口变化,由之前的窗口变为了com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI。
这时候,我们可以继续利用对节点的遍历来实现点击的动作。代码如下:

 AccessibilityNodeInfo openRedbagbtn = findFuctionButtonNode(nodeInfo,OPENBUTTON);
        if(openRedbagbtn==null) {
            AccessibilityNodeInfo closeButton = findFuctionButtonNode(nodeInfo,CLOSEBUTTON);
            return;
        }

        openRedbagbtn.performAction(AccessibilityNodeInfo.ACTION_CLICK);
        setOpenredbagState(false);
......

 private AccessibilityNodeInfo findFuctionButtonNode(AccessibilityNodeInfo nodeInfo,int fun) {
        AccessibilityNodeInfo FuctionButton;
        int chirdCount = nodeInfo.getChildCount();
        switch (fun) {
            case OPENBUTTON:
                for(int i=0;i<chirdCount;i++) {
                //因为打开的页面只有一个打开按钮,所以根据button来找就可。                  if(nodeInfo.getChild(i).getClassName().equals("android.widget.Button"))
                        return  nodeInfo.getChild(i);
                }
                break;
            case CLOSEBUTTON:
                ......
            default:break;
        }

        return null;
    }

至此,基本自动抢红包的功能都完成了。为了保证程序的健壮性,还需要对抢红包的失败的情况进行处理。
具体代码已传GIT,异常处理可能有不全的地方,待感冒好了再改了 蓝瘦。
git:https://github.com/everyhappy/RedRUsh

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值