您的位置:首页 > 移动开发 > 微信开发

[置顶] 300行代码实现 微信或QQ 抢红包功能

2016-12-28 11:31 951 查看
每次看到别人发红包,但是没有抢到,这就很尴尬了。于是想着做一个红包插件,嘿嘿,再也不怕我反应迟钝了。

首先,想到做这个功能时,我联想到的是这个是不是lua写出来的脚本呢?但是条件不成立,因为可以不需要ROOT的。那么问题就来了,这玩意怎么实现?网上查了查,这下子明白了,Android平台为了给一些使用手机不是很方便的人提供了一个解决方案,被叫做AccessibilityService。这是一个辅助类,用于监听手机的焦点,窗口变化,按钮点击等等。

接下来,分析了源码上的绿色字体,大致意思如下:

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

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

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

声明
必须完成2件事:
1.指定处理”android.accessibilityservice.AccessibilityService
”
2.请求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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐