AccessibilityService是Google专门为残障人士设计的一个服务,可以让他们更方便的来操作手机。AccessibilityService一个主要功能是通过监听窗口的变化来判断用户当前正在做什么,它可以监听到窗口焦点的变化,Activity的跳转,Activity中View的变化等等,通过监听窗口的这些变化我们来猜测用户正在做什么,从而模拟出一些操作。很早的时候,一些应用市场想要实现App的静默安装必须获取root权限,但是获取手机的root权限谈何容易?Google从Android6.0开始加强了root权限的管理,意味着Android6.0之后想要获取root权限将变得更加困难,于是有的应用市场,比如豌豆荚最早推出了免root自动升级或者安装应用的功能,豌豆荚就是利用这个AccessibilityService来实现的,当我们安装App的时候,系统都会弹出安装确认框,AccessibilityService看到安装二字的时候就去自动模拟点击这个按钮,从而实现免root应用的安装升级;AccessibilityService的另一个使用场景就是我们今天要说了抢红包神器啦!

Google为残障人士设计的AccessibilityService被天朝的程序员们玩坏了!

1.设计思路

先来说说实现思路吧,这个其实很简单,首先微信抢红包的过程可以分为两部分,第一步就是红包来了抢红包,第二步就是拆红包,我们的自动抢红包就是根据这两个步骤来实现。我们通过AccessibilityService来监测手机屏幕的变化,当发现有“领取红包”红包字样的时候,就点击该控件,从而进入到拆红包的页面,在该页面再获取拆红包的按钮,然后模拟点击该按钮,从而将money收入囊中,OK,这就是我们的一个整体思路。这里边有一个稍微麻烦的问题,就是怎样判断一个红包是否已经被抢过了,因为微信红包中抢过和没抢过的红包是一模一样的,所以很难从表面上进行区分,考虑到微信的聊天页面是使用ListView来实现的,每一条消息实际就是ListView中的一个item,所以这里我打算记录下当前页面所有红包消息的hashCode,同时又考虑到item会复用,即即将显示的item有可能是刚刚回收的item,这会导致hashCode重复,于是我采用一个HashSet来记录当前页面所有拆开红包的hashCode,每当要抢一个红包的时候,我都先判断该红包的hashCode是否已经存在于HashSet中,如果存在说明该红包已拆开,否则说明红包没被拆开过,此时将红包拆开,同时将该红包的hashCode存入hashSet中。另外,我还需要监测当前页面第一个红包的HashCode,如果第一个红包滑出当前页面,则将其对应的hashCode从HashSet中移除。OK,这就是整体思路。关于如何记录已拆开的红包,如果小伙伴们有更好的方式欢迎留言讨论。

2.编码实现

这里的代码也不难,整体上三个步骤:

1.自定义类继承自AccessibilityService,在该类中实现抢红包的逻辑代码

2.xml中对自定义的AccessibilityService进行配置

3.清单文件中配置服务

OK,我们就根据上面的三个步骤来实现抢红包吧。

1.定义RedPacketsAccessibilityService

public class RedPacketsAccessibilityService extends AccessibilityService {

    private Set<Integer> currentScreenRedPackets = new HashSet<>();
private int lastFirstVisiableRedPackets; @Override
public void onCreate() {
super.onCreate();
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher).setContentTitle("红包神器运行中");
startForeground(1, builder.build());
} @Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getSource() != null) {
AccessibilityNodeInfo rootInActiveWindow = getRootInActiveWindow();
if (rootInActiveWindow != null) {
if (event.getEventType()==AccessibilityEvent.TYPE_VIEW_SCROLLED) {
//抢红包
List<AccessibilityNodeInfo> list = rootInActiveWindow.findAccessibilityNodeInfosByText("领取红包");
if (list != null && list.size() > 0) {
AccessibilityNodeInfo firstNode = list.get(0);
if (lastFirstVisiableRedPackets != firstNode.hashCode()) {
currentScreenRedPackets.remove(lastFirstVisiableRedPackets);
lastFirstVisiableRedPackets = firstNode.hashCode();
}
for (int i = list.size() - 1; i > -1; i--) {
AccessibilityNodeInfo nodeInfo = list.get(i);
if (!currentScreenRedPackets.contains(nodeInfo.hashCode())) {
AccessibilityNodeInfo parent = nodeInfo.getParent();
if (parent != null) {
parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
currentScreenRedPackets.add(nodeInfo.hashCode());
break;
}
}
}
}
}
//拆红包
List<AccessibilityNodeInfo> nodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/bdg");
if (nodeInfoList != null && nodeInfoList.size() > 0) {
for (AccessibilityNodeInfo accessibilityNodeInfo : nodeInfoList) {
accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
} @Override
public void onInterrupt() { }
}

AccessibilityService的使用我就不必多说了吧,这里我就简单说一下抢红包的过程,进入到onAccessbilityEvent方法中之后,如果该方法是由页面滚动触发的,则进入抢红包的逻辑判断,抢红包的时候,先来获取当前页面所有包含’领取红包‘字样的所有控件,然后遍历该控件,判断hashSet中是否有该控件的hashCode,有的话就拆红包。

2.xml中进行配置

在res目录下新建一个xml文件夹,在里边创建一个xml配置文件,这个配置现在也可以放在AccessbilityService的onCreate方法中执行:

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

accessibilityEventTypes表示要监听屏幕的哪些事件,typeAllMask表示监听所有事件,比如屏幕滚动,页面跳转等。android:accessibilityFeedbackType表示设置反馈方式,feedbackGeneric表示通用反馈模式。其他属性见名知意,不再赘述。

3.清单文件中配置服务

凡是服务,都需要在清单文件中进行配置,AccessibilityService也不例外,配置方式如下:

<service
android:name=".RedPacketsAccessibilityService"
android:enabled="true"
android:label="红包神器"
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_config"/>
</service>

注意metadata中配置的resource指向第二步创建的xml文件。OK,这样就可以了。

3.其他

有的小伙伴疑惑我怎么知道微信中页面结构等等信息,其实很简单,利用SDK中提供的uiautomatorviewer工具即可,在sdk的tools目录下,使用如下图:

OK,关于微信红包神器的介绍我们就说这么多,有问题欢迎留言讨论。

项目开源地址https://github.com/lenve/RedPackets

欢迎小伙伴们star、fork,pr。

App下载地址http://pan.baidu.com/s/1bBGaBW

以上。

玩转Android之手摸手教你DIY一个抢红包神器!的更多相关文章

  1. iOS动画进阶 - 手摸手教你写 Slack 的 Loading 动画

    如果移动端访问不佳,可以访问我的个人博客 前几天看了一篇关于动画的博客叫手摸手教你写 Slack 的 Loading 动画,看着挺炫,但是是安卓版的,寻思的着仿造着写一篇iOS版的,下面是我写这个动画 ...

  2. 手摸手教你如何在 Python 编码中做到小细节大优化

    手摸手教你如何在 Python 编码中做到小细节大优化 在列表里计数 """ 在列表里计数,使用 Python 原生函数计数要快很多,所以尽量使用原生函数来计算. &qu ...

  3. 手摸手教你微信小程序开发之自定义组件

    前言 相信大家在开发小程序时会遇到某个功能多次使用的情况,比如弹出框.这个时候大家首先想到的是组件化开发,就是把弹出框封装成一个组件,然后哪里使用哪里就调用,对,看来大家都是有思路的人,但是要怎样实现 ...

  4. 手摸手教你让Laravel开发Api更得心应手

    https://www.guaosi.com/2019/02/26/laravel-api-initialization-preparation/ 1. 起因 随着前后端完全分离,PHP也基本告别了v ...

  5. 【转】手摸手,带你用vue撸后台 系列一

    前言 说好的教程终于来了,第一篇文章主要来说一说在开始写业务代码前的一些准备工作吧,但这里不会教你webpack的基础配置,热更新怎么做,webpack速度优化等等,有需求的请自行google. 目录 ...

  6. 手摸手带你用Hexo撸博客(一)

    原文地址 手摸手带你用Hexo撸博客(一) 环境搭建 安装 node 狂点下一步 命令行输入此条命令 如果能看到版本号则安装成功 node -v 安装Git (同上) 实在不会的小伙伴百度一下,教程很 ...

  7. 手摸手,和你一起学习 UiPath Studio

    学习 RPA 的路上坑比较多,让我们手摸手,一起走…… 以下是一些学习 UiPath 和 RPA 的资源, 拿走不用谢! UiPath Studio 中文文档 机器人流程自动化其实是很好的概念和技术, ...

  8. 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)

    前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...

  9. 【转】手摸手,带你用vue撸后台 系列三(实战篇)

    前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...

随机推荐

  1. MFC使用ShowWindow(SW_MAXIMIZE)任务栏消失的处理

    ShowWindow(SW_SHOWMAXIMIZED);//窗口最大化 问题:在写程序时,如果包含了标题栏,但是没有包含最大化按钮或者最小话按钮. 那么人工用ShowWindow(SW_MAXIMI ...

  2. Namespaces(命名空间)

    datastore,Blobstore,memcache一起为应用存储数据.这对于在全球范围内分割数据是有用的.比如,一个应用可以为多个公司服务,每个公司可以看到它自己的隔离的应用实例,没有公司可以看 ...

  3. cocos2d-x 纹理深入研究 第二部分

    转自:http://blog.csdn.net/qq51931373/article/details/9152227 1.纹理控制. 看此代码: CCSprite *pSprite = CCSprit ...

  4. 各个版本spring的jar包以及源码下载地址

    各个版本spring的jar包以及源码下载地址,目前最高版本到spring4.1.2,留存备用: http://maven.springframework.org/release/org/spring ...

  5. LCD1602汉字、自定义字符取模

    用zimo221软件, 新建一个8*8的图像,留出左边3列,用右边5列点出自定义字符,选择取模方式C51,就可得到对应的编码 如下图:温度符号℃的编码

  6. [iOS 多线程 & 网络 - 2.4] - 大文件下载 (边下边写/暂停恢复下载/压缩解压zip/多线程下载)

    A.需求 边下边写入硬盘 显示下载进度 暂停/恢复 下载 解压文件 多线程下载   B.基本知识 1.小文件下载 如果文件比较小,下载方式会比较多直接用NSData的+ (id)dataWithCon ...

  7. HDU 1068 Girls and Boys (二分图最大独立集)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1068 有n个同学,格式ni:(m) n1 n2 n3表示同学ni有缘与n1,n2,n3成为情侣,求集合 ...

  8. Java中的Filter过滤器

    Filter简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 ...

  9. python的sys.path

    python检测不到模块: No module named 是因为模块没有在sys.path中,查看sys.path的方法 import sys sys.path 发现确实没有加载到模块. windo ...

  10. c#与java webservice调用问题

    问题描述一: c#调用java写的websrevice,对方接收到的参数与实际传的值不一致,返回的时候值也获取不到,为null. 该参数为普通的string类型,因此不存在类型转换的问题. 处理: 使 ...