上一章《AccessibilityService讲解》我们对AccessibilityService做了基本的讲解,本章我们就利用AccessibilityService做一个抢红包插件。

1.前言

本章编写的代码仅供个人学习使用,禁止用于其他非法行为。技术是把双刃剑希望大家正确对待!

在文章的开头奉送上代码,方便大家对照着学习。

2.代码编写

2.1抢包流程:

做抢红包的插件我们得一步一步来,首先我们应该了解抢红包的流程是怎么样的,回顾一下抢红包的流程:

1. 状态栏出现”[微信红包]”的消息提示,点击进入聊天界面
2. 点击相应的红包信息,弹出抢红包界面
3. 在抢红包界面点击”开”,打开红包
4. 在红包详情页面,查看详情,点击返回按钮返回微信聊天界面.

上面就是抢红包的整个流程。虽然这是整个流程,但是当前微信处于的界面可能出现以下几种:

1.微信在后台运行,而当前手机在浏览其他APP(需要执行1->2->3->4)
2.当前处于微信的首页(需要执行1->2->3->4)
3.处于和某个人聊天的页面(2->3->4)

2.1代码编写

理解了抢红包的流程,我们开始编写代码。上一节讲了,创建一个AccessibilityService的流程很简单如下:
1.继承AccessibilityService类,重写里面的方法
2.在AndroidMainifest中注册
3.添加配置文件

1.下面我们来看一下AccessibilityService的编写

package com.czh.service;
import java.util.ArrayList;
import java.util.List;
import android.accessibilityservice.AccessibilityService;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;/*** @author 作者 YYD* @version 创建时间:2016年12月14日 下午2:46:49* @function 未添加*/
public class RobService extends AccessibilityService {/*** 此方法用来接收我的需要的各种事件 在accessibility.xml中我们监听了以下事件:* typeNotificationStateChanged typeWindowStateChanged* typeWindowContentChanged* http://www.jianshu.com/p/ba298b8d5a6e  看看这个是否被拆了判断*/@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {int eventType = event.getEventType();switch (eventType) {// 当通知栏发生改变的时候case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: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 {pendingIntent.send();} catch (Exception e) {}}}}}break;// 当窗口内容发生改变的时候case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:break;// 当窗口状态发生改变的时候case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:String className = event.getClassName().toString();if (className.equals("com.tencent.mm.ui.LauncherUI")) { //聊天页
//              getLastPacket();//注释的原因我在方法中写明了,如果放开这个方法就会出现死循环,大家可以尝试一下。
//              inputClick("com.tencent.mm:id/fz");//这条语句是聊天页面返回键的id,放不放开都没用。} else if (className  //拆红包页,点击“开”,抢红包.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) {inputClick("com.tencent.mm:id/bg7");} else if (className //红包详情页,点击返回键.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) {inputClick("com.tencent.mm:id/gd");}break;}}/*** 根据id,获取AccessibilityNodeInfo,并点击。*/private void inputClick(String clickId) {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if (nodeInfo != null) {List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(clickId);for (AccessibilityNodeInfo item : list) {item.performAction(AccessibilityNodeInfo.ACTION_CLICK);}}}
/*** 这个方法有缺陷。要是能加 过滤已拆红包就好了。我实在想不出好的办法所以注释掉了。* 如果大家有好的过滤方案,请告诉我一声,不胜感激!这是我的一个遗憾* 因为这一行注释掉,就不是我们想要的全自动的抢红包了。*/private void getLastPacket() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();recycle(nodeInfo);if (parents.size() > 0) {parents.get(parents.size() - 1).performAction(AccessibilityNodeInfo.ACTION_CLICK);}}@Overridepublic void onInterrupt() {}@Overrideprotected void onServiceConnected() {super.onServiceConnected();Toast.makeText(RobService.this, "成功与微信绑定,开始监听", Toast.LENGTH_SHORT).show();}ArrayList<AccessibilityNodeInfo> parents = new ArrayList<AccessibilityNodeInfo>();
/*** 这个方法是用递归的方式,遍历节点树。* 如果找到“领取红包”和“查看红包”所在叶子节点,就用while不断的找自己父节点,这个父节点要求可以被点击。(也是是说找最近一个可以点击的父节点)*/private void recycle(AccessibilityNodeInfo info) {if (info.getChildCount() == 0) {if (info.getText() != null) {if ("领取红包".equals(info.getText().toString())||"查看红包".equals(info.getText().toString())) {
//                  if (info.isClickable()) {//                      info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
//                  }AccessibilityNodeInfo parent = info.getParent();while (parent != null) {if (parent.isClickable()) {parents.add(parent);//找到了添加到列表并推出循环,否则继续往上找父节点。break;}parent = parent.getParent();}}}} else {for (int i = 0; i < info.getChildCount(); i++) {if (info.getChild(i) != null) {recycle(info.getChild(i));}}}}@Overridepublic boolean onUnbind(Intent intent) {Toast.makeText(this, "断开与微信绑定,停止监听", Toast.LENGTH_SHORT).show();return super.onUnbind(intent);}
}

这里我们对一些语句做一些解释:

1.getRootInActiveWindow(); //获取当前窗口的根节点。
2.findAccessibilityNodeInfosByViewId//根据id获取节点,获取的是一个列表
3.AccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);//模拟点击事件
4.AccessibilityNodeInfo.getParent()获取父节点

2.MainActivity类的编写

public class MainActivity extends Activity implements OnClickListener{private Button settingBtn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findView();}private void findView(){settingBtn = (Button) findViewById(R.id.settingBtn);settingBtn.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.settingBtn://跳转到辅助设置页Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);startActivity(intent);break;}}
}

3.看一下menifest中的注册

     <service
            android:name="com.czh.service.RobService"android:enabled="true"android:exported="true"android:label="@string/servicelable"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/accessibility" /></service>

这里对menifest讲解一下:

android:label="@string/servicelable"是服务描述

效果如下:

<serviceandroid:name="com.czh.service.RobService"android:enabled="true"android:exported="true"android:label="@string/servicelable"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" ><intent-filter><action android:name="android.accessibilityservice.AccessibilityService" /></intent-filter></service>

这一块是固定的写法,没什么好说的。注意权限是必须要加上!

<meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility" />

meta-data是配置文件,配置信息在accessibility.xml中

3.看一下accessibility.xml文件
在res文件夹下面新建一个文件夹xml –> 在xml文件夹中新建一个accessibility.xml文件。

<?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="flagDefault"android:canRetrieveWindowContent="true"android:notificationTimeout="100"android:description="@string/description"android:packageNames="com.tencent.mm" />

对这个accessibility.xml讲解一下:

1.android:accessibilityEventTypes 表示监听的事件类型,这本章中我们监听通知,屏幕状态变化,屏幕内容变化。typeAllMask表示监听所有类型
2.android:accessibilityFeedbackType 表示手机用什么方式将信息反馈给用户,语音震动等等,这里默认;
3.android:canRetrieveWindowContent="true",允许检索窗口内容,这一条必须要加上。
4.android:description 描述
5.android:packageNames="com.tencent.mm"这里我们监听微信的包名,如果你想监听多个App的话可以这样写:
android:packageNames="com.tencent.mm|com.tencent.qq"

在配置文件中android:description添加后的效果图是这样的:

3.看一下strings.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">微信抢红包</string><string name="servicelable">微信自动抢红包</string><string name="description">本插件仅供娱乐,切勿用于不当用途,出现问题后果自负!</string>
</resources>

3.补充

大家可能在想,findAccessibilityNodeInfosByViewId()方法中的ID是如何知道的呢?下面我们就来解释一下:
在devices中有这么一个按钮,点击进入,效果图如下:

进入之后你会看到下面界面:

通过图你可以看出,左面是界面,又面是布局和控件的详细信息(我们可以通过这个来学习人家的布局规律),当你点击某个控件的时候,右面就会显示该控件的信息,图中我们标记出来了。

4.不足之处

我在写这个东西上时候有一个bug,一直不知道如何解决:新版微信无法区分未拆红包和已拆红包。就是因为这个原因程序会把已拆红包当成未拆红包来拆,导致死循环,如果有知道解决方案的朋友请告知我,不胜感激!

5.结尾

在文章的结尾奉送上代码,方便大家对照着学习。

在技术上我依旧是个小渣渣,加油勉励自己。

android拆轮子系列之一步一步教你写微信抢红包插件相关推荐

  1. 拆轮子系列--RxJava理解(一)--Map解析

    本系列文章如下: 拆轮子系列--RxJava前奏篇 拆轮子系列--RxJava理解(一)--Map解析 拆轮子系列--RxJava理解(二)--subscribeOn 拆轮子系列--RxJava理解( ...

  2. 拆轮子系列之教你一步步写验证码控件

    拆轮子系列之教你一步步写验证码控件 前言 先看看效果 怎么样不错吧?别急下面我就一步一步的教你实现. 用到的知识点总结: 1.Canvas和pint的使用,我们用它画点,线,字 2.View的基本用法 ...

  3. 拆轮子系列--RxJava理解(三)--observeOn

    本系列文章如下: 拆轮子系列--RxJava前奏篇 拆轮子系列--RxJava理解(一)--Map解析 拆轮子系列--RxJava理解(二)--subscribeOn 拆轮子系列--RxJava理解( ...

  4. android黑科技系列——微信抢红包插件原理解析和开发实现

    一.前言 自从几年前微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导 ...

  5. Android微信抢红包插件原理和实现 适配微信6.6.1版本

    Android微信抢红包插件原理和实现 适配微信6.6.1版本 一.前言 年关将至,小伙伴们又聊起了春节长假的旅行安排和各自家乡的年味习俗,不一而足.其中在各个微信群聊中抢红包也是为大家所津津乐道的. ...

  6. Android 微信抢红包插件

    转载开源工程:https://github.com/geeeeeeeeek/WeChatLuckyMoney 这个Android插件可以帮助你在微信群聊抢红包时战无不胜.当检测到红包时,插件会自动点击 ...

  7. Android微信抢红包插件源码解析

    这个Android插件可以帮助你在微信群聊抢红包时战无不胜.当检测到红包时,插件会自动点击屏幕,人工点击的速度无法比拟. 你正在查看的是dev分支,这个分支包含大量实验性的修改,不再更新.如果你希望有 ...

  8. Android 辅助功能(无障碍)自定义开发类似微信抢红包插件

    背景: 通常在无人值守的Android智能设备或不能触摸交互的设备中,当系统运行异常时, 系统有可能会弹出应用程序无响应(ANR)对话框,提示是否终止当前进程或等待,或应用程序异常退出时系统偶尔也会有 ...

  9. 微信抢红包插件 android 8.0,重磅!微信8.0专属红包全量上线!

    "本文由我原创,来源 

  10. Android一步一步实现一款实用的Android广告栏

    源码:BannerLayoutDemo 有图有真相: bannerLayoutDemo 开源界有一句很有名的话叫"不要重复发明轮子",当然,我今天的观点不是要反驳这句话,轮子理论给 ...

最新文章

  1. ecshop手机端html,ECSHOP手机版本的head标题的修改方法分享
  2. python消息推送_Python阿里云消息推送调用API
  3. Python基础概念_14_常见术语
  4. 多继承以及MRO顺序【super().的使用】
  5. java mysql实现原理_MySQL事务实现原理
  6. java绘制图表控件_eclipse中用JAVA代码怎么画柱形图表
  7. SQL server 数据库基础知识之数据类型
  8. CakePHP 2.x CookBook 中文版 第七章 模型 之 数据校验
  9. 《AI算法工程师手册》读书笔记(1)
  10. JS判断数组元素是否重复
  11. php pdf怎么转换成jpg图片,如何在线将pdf转换成jpg图片格式?
  12. php获取服务器运行时间差,解决php服务器时间差异
  13. android发送短信的两种方式,发送长短信的两种方式,群发短信
  14. ReflectionTestUtils.invokeMethod方法的使用
  15. 在手机上怎么提取视频中的音频?就这么简单
  16. ubuntu-安装Wine
  17. 水平居中和垂直居中css_如何使用CSS将图像垂直和水平居中
  18. Unity 语音识别 详情版 和 发布过程中遇到的问题
  19. Goldwave心得
  20. ffmpeg 下载后缀为.m3u8的视频文件

热门文章

  1. 机器人对话常用语模板_小a电话机器人免费咨询
  2. Spire.Doc 指定位置插入书签和获取书签内容
  3. MQTT基础--MQTT 客户端和代理以及 MQTT 服务器和连接建立说明:第 3 部分
  4. GB35114—①、术语、定义和缩略语
  5. webstorm使用指南
  6. 英文参考文献的著录规范
  7. axure通用元件库 Pc、Web端原型图组件库高保真UI rp源文件
  8. 大数据入门介绍和学习路线
  9. lqr控制和模糊控制三级倒立摆
  10. oracle instant client卸载,Oracle Instant Client(即时客户端) 安装与配置