300行代码实现 微信或QQ 抢红包功能

每次看到别人发红包,但是没有抢到,这就很尴尬了。于是想着做一个红包插件,嘿嘿,再也不怕我反应迟钝了。
首先,想到做这个功能时,我联想到的是这个是不是lua写出来的脚本呢?但是条件不成立,因为可以不需要ROOT的。那么问题就来了,这玩意怎么实现?网上查了查,这下子明白了,Android平台为了给一些使用手机不是很方便的人提供了一个解决方案,被叫做AccessibilityService。这是一个辅助类,用于监听手机的焦点,窗口变化,按钮点击等等。
接下来,分析了源码上的绿色字体,大致意思如下:

无障碍服务的开发需要扩展这个类并实现其抽象方法。

生命周期
由系统和遵循已建立的服务生命周期

当用户在设备设置中或在设备设置期间关闭时,无障碍服务将停止

声明
必须完成2件事:
1.指定处理”android.accessibilityservice.AccessibilityService2.请求android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE权限使有且仅有系统可以绑定。

两种配置方法:
1.在manifest中设置;
2.在代码类中动态设置。

辅助功能可以配置为特定类型的辅助功能事件,仅监听特定的包,在给定的时间内做指定的事。

继续往下看代码,Callbacks里有onAccessibilityEvent、onInterrupt和onServiceConnected是很重要的。

关于onAccessibilityEvent,源码的解释:

  The new event. This event is owned by the caller and cannot be used after this method returns. Services wishing to use the event after this method returns should  make a copy.

意思大致是我们需要继承AccessibilityService,然后实现onAccessibilityEvent方法。

关于onInterrupt,源码的解释:

Callback for interrupting the accessibility feedback.

这个是用功能中断时回调。

关于onServiceConnected,源码的解释:

This method is a part of the {@link AccessibilityService} lifecycle and is called after the system has successfully bound to the service. If is convenient to use this method for setting the {@link AccessibilityServiceInfo}.

系统成功绑定后回调,前面提到的代码配置也是在这个方法内。

好了,源码看到这里。我们需要的几个方法都了解了,接下来直接来看代码。首先创建工程,然后创建一个RBAccessibilityService继承自AccessibilityService。实现onAccessibilityEvent、onInterrupt和onServiceConnected方法。然后配置manifest

<service
               android:name=".service.RBAccessibilityService"
               android:exported="true"
               android:enabled="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/accessibilityservice_set">
               </meta-data>
          </service>

我们需要注意的是meta-data里的resource,这里需要在res创建一个xml文件夹,写入如下代码:

<accessibility-service
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:accessibilityEventTypes="typeAllMask"
     android:accessibilityFeedbackType="feedbackSpoken"
     android:accessibilityFlags="flagDefault"
     android:canRequestTouchExplorationMode="true"
     android:canRetrieveWindowContent="true"
     android:notificationTimeout="50"
       android:description="@string/accessibility_description"
     android:packageNames="com.tencent.mobileqq,com.tencent.mm"/>

packageNames里的是需要监听的包名,需逗号隔开。配置完成,继续实现具体代码,完善RBAccessibilityService的onAccessibilityEvent:

@Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
          String className = event.getClassName().toString();
          switch (event.getEventType()) {
               //通知栏
               case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                    List<CharSequence> texts = event.getText();
                    if (!texts.isEmpty()) {
                         for (CharSequence text : texts) {
                              String content = text.toString();
                              /**
                               * 微信的notification
                               */
                              if (content.contains(WECHAT_RB_TEXT)) {
                                   //赋值给判断值
                                   QQ_OR_WECHAT = THISWECHAT;
                                   RBnotification(event);
                              }
                              /**
                               * QQ的notification
                               */
                              if (content.contains(QQ_RB_TXT)) {
                                   //赋值给判断值
                                   QQ_OR_WECHAT = THISQQ;
                                   RBnotification(event);
                              }
                         }
                    }
                    break;
               case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                    //判断是QQ或者微信发送来的红包
                    if (QQ_OR_WECHAT == THISQQ) {
                         openQQHongBao(event);
                    } else {
                         openWeChatHongBao(event);
                    }
                    break;
               case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                    break;
               default:
                    break;
          }
     }

看明白了么?这个方法内TYPE_NOTIFICATION_STATE_CHANGED状态就是监听微信或QQ发送红包过来时出现的notification,然后通过这个notification进入出现该红包的聊天页面。这个时候
窗口状态也变换了,又运行到了TYPE_WINDOW_STATE_CHANGED这个状态,这时我们的微信或QQ应该还是在聊天页面,接下来去实现点击或打开功能。需要注意的是,微信打开红包需要两次点击,先是领取,然后打开,但是QQ只需要一次点击,微信红包较简单,只有一种类型,QQ红包类型有两种。所以我们应该在窗口变化之前监听是QQ还是微信发送过来的红包,然后根据不同的值去做不同的动作。

QQ红包

//检测到QQ红包
     private void openQQHongBao(AccessibilityEvent event) {
          state_qq = STATE_NO_QQ;
//          getRunningActivityName();
          if ("cooperation.qwallet.plugin.QWalletPluginProxyActivity".equals(event.getClassName())) {
               state_qq = STATE_OPENED_QQ;
               if (RBSharedPerences.readRBQQState(getApplicationContext(), STATE_CODE_QQ).equals(state_qq)) {
                    performGlobalAction(GLOBAL_ACTION_HOME);
                    RBSharedPerences.writeRBQQstate(getApplicationContext(), STATE_CODE_QQ, STATE_NO_QQ);
               }
          } else if ("com.tencent.mobileqq.activity.SplashActivity".equals(event.getClassName())) {
               //拆红包
               state_qq = STATE_CLIECKED_QQ;
               openQQPacket();
          }
     }

     //领取打开QQ红包
     private void openQQPacket() {
          AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
          if (nodeInfo != null) {
               AccessibilityNodeInfo targetNode = null;
               targetNode = findNodeInfosByText(nodeInfo, RB_BUTTON_TEXT_NAME);
               //普通红包
               if (targetNode != null) {
                    performClick(targetNode);
                    RBSharedPerences.writeRBQQstate(getApplicationContext(), STATE_CODE_QQ, STATE_OPENED_QQ);
               }
               //口令红包
               else {
                    AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
                    if (accessibilityNodeInfo != null) {
                         List<AccessibilityNodeInfo> nodeInfos = accessibilityNodeInfo
                                   .findAccessibilityNodeInfosByText(RB_PASSWORD);
                         for (AccessibilityNodeInfo nodeInfo1 : nodeInfos) {
                              targetNode = nodeInfos.get(nodeInfos.size() - 1);
                              performClick(targetNode);
                              writePassword();
                         }
                    }
               }
          }
     }

     //写入并发送口令
     private void writePassword() {
          AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
          if (accessibilityNodeInfo != null) {
               findWidgetByText(accessibilityNodeInfo, RB_CLICK_TO_PASTE_PASSWORD);
          }
          if (accessibilityNodeInfo != null) {
               findWidgetByText(accessibilityNodeInfo, SEND_PASSWORD);
               RBSharedPerences.writeRBQQstate(getApplicationContext(), STATE_CODE_QQ, STATE_OPENED_QQ);
          }
     }

这里面有个巧妙的点,就是开始时我始终找不到红包RelativeLayout的ID,那可怎么办呢,我继续往外层查找,红包外层还是一层RelativeLayout,但是content-desc中的值是 “xxxx,点击查看详情”。
查找普通红包
明白了吗?没错,我通过文本查找遇到有文字包含有这个时再去实现点击nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
那么口令红包又是如何实现的呢?同理,也是需要通过文本查找文字
查找口令红包
但是这里直接查找”口令红包”就可以了,查找到后实现点击,QQ会自动给我们出现一个按钮在输入框上方
点击输入口令
继续查找文本并点击”点击输入口令”,这时候,输入框就有口令了,那么查找到发送的文本再实现一次点击,红包就领取成功了。

微信红包

//检测到微信红包
     private void openWeChatHongBao(AccessibilityEvent event) {
          state = STATE_NO;
//          getRunningActivityName();
          if ("com.tencent.mm.ui.LauncherUI".equals(event.getClassName())) {
               //点中红包
               getWeChatPacket();
          } else if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(event.getClassName())) {
               //拆红包
               openWeChatPacket();
          } else if ("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(event.getClassName())) {
               state = STATE_OPENED;
               //拆完红包后返回
               if (RBSharedPerences.readRBWeChatState(getApplicationContext(), STATE_CODE).equals(state)) {
                    performGlobalAction(GLOBAL_ACTION_HOME);
                    RBSharedPerences.writeRBWeChatState(getApplicationContext(), STATE_CODE, STATE_NO);
               }
          }
     }

//领取红包
     private void getWeChatPacket() {
          AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
          if (accessibilityNodeInfo != null) {
               findWidgetByText(accessibilityNodeInfo, GET_RB_TEXT);
          }
     }

     //拆开红包
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     private void openWeChatPacket() {
          AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
          if (nodeInfo != null) {
               AccessibilityNodeInfo targetNode = null;
               targetNode = findNodeInfosByClassName(nodeInfo, RB_BUTTON_CLASS_NAME);
               performClick(targetNode);
               //设置值
               RBSharedPerences.writeRBWeChatState(getApplicationContext(), STATE_CODE, STATE_OPENED);
          }
     }

微信的红包和QQ 不一样的地方在于需要先点开红包出现一个红包页面,再点击红包才会打开红包。点开红包查找文本”领取红包”并实现点击,这时页面进入”com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI”
打开微信红包
这时候显然通过文本查找是不行的了,因为这里只是一个Button,并没有文字,所以说需要另辟蹊径,因为当前页面仅有这一个Button,所以我们可以通过控件具体名字查找控件。

     //通过组件名字查找
     public static AccessibilityNodeInfo findNodeInfosByClassName(AccessibilityNodeInfo nodeInfo, String className) {
          if (TextUtils.isEmpty(className)) {
               return null;
          }
          for (int i = 0; i < nodeInfo.getChildCount(); i++) {
               AccessibilityNodeInfo node = nodeInfo.getChild(i);
               if (className.equals(node.getClassName())) {
                    return node;
               }
          }
          return null;
     }

再实现一个点击事件。perfect,微信红包领取成功。

一个抢红包功能就这么愉快的搞定了!!快去试试吧!!你的点赞是对我最好的支持!!谢谢!!

最后附上CSDN下载链接和github的链接

http://download.csdn.net/detail/a876980961/9723236
https://github.com/a876980961/pop_hongbao_assistant

  • 14
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值