通过抢红包插件学习Accessibility Service

我们时常会遇到一些人使用 ”抢红包”插件来帮忙抢红包,它实际上就是通过Android上常见的Accessibility Services功能实现的,今天咱们通过这个插件来聊一下Accessibility Services

1 什么是Accessibility Services

概述

Accessibility Services是为一些有障碍人士使用Android设备和应用所提供的,它在后台运行,并当AccessibilityEvents被触发时接受系统的回调,这些Events表示在用户界面某些状态的转换,比如说焦点的变换,一个Button被点击等等,AccessibilityEvents后面也会说到,这个Services可以有选择地请求和查询活动窗口内容的能力。

Lifecycle

Accessibility Services的生命周期由系统专门管理,并且遵循既定服务的生命周期,启动Accessibility Services完全是由用户在设置中打开并触发。系统在绑定Services之后将调起onServiceConnected()。这个方法可以由客户端继续重写,做重新配置。

摘自:https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityService.html

2 如何使用

AndroidMainfest声明Services

Accessibility跟其他Services一样,都需要在 AndroidManifest.xml中进行声明,但是它必须做两件事情:

  • 它必须设置Intent的Action:“android.accessibilityservice.AccessibilityService”
  • 声明请求 BIND_ACCESSIBILITY_SERVICE 权限,确保只能系统才能绑定到它

上面两点中如果有任意一项缺失系统将忽略 Accessibility Services

声明

配置Services

一个Accessibility Services可以通过配置来接收特殊类型的 AccessibilityEvents。可以通过两种方式进行配置:

  • 在Mainfest中声明Accessibility Services时提供一个meta-data ,如上图中所示,其中配置文件可参考下图
image.png
  • 调用 setServiceInfo(AccessibilityServiceInfo) . 注意,这个方法可以随时调用去更改Services的配置。

    注:这个方法只能允许设置动态可配置的属性有: eventTypes, feedbackType, flags, notificationTimeout, packageNames

检索窗口内容(Retrieving window content)

新建一个继承自AccessibilityService的类,实现它的两个抽象方法onAccessibilityEvent和onInterrupt。用于检索窗口信息。我们将在后面实现抢红包插件的地方详细说明。

image.png
  • onAccessibilityEvent(AccessibilityEvent event) 此事件由调用方拥有,此方法返回后不能使用。希望在此方法返回后使用事件的服务应该复制。(???)窗体上有什么变化都会回调该方法.
  • onInterrupt() 中断accessibility反馈的回调

Accessibility Services可以在它的声明中指定检索窗口的内容, 这些内容被表示成AccessibilityWindowInfo树或者AccessibilityWindowInfo对象的形式。值得注意的是,这些声明需要通过上文提到的meta_data中的xml文件中配置.

注:Accessibility Services可能已经请求通知了事件类型的子集,因此当节点层次结构发生更改时可能并不知情。由于窗口内容可能随时发生更改,所以节点也可能包含过时的信息。

Note An accessibility service may have requested to be notified for a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also possible for a node to contain outdated information because the window content may change at any time.

打开辅助功能权限

要想使用Accessibility Services就必须让用户手动打开辅助功能的权限。可以用下面的方法来检测是否开启了辅助功能权限:

image.png

如果检查没有该权限,可以使用startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));去引导用户打开辅助功能权限。

3 抢红包插件开发

完成配置

根据上一小节内容,完成在AndroidMainfest.xml中的声明以及在xml中配置。新建一个RedEnvelopAccessibility继承自AccessibilityService,实现其两抽象方法.

分析微信抢红包页面

通过打开Android SDK自带的uiautomatorviewer来分析微信抢红包的页面信息。

image.png

我们要分析三个页面:

  1. 收到红包的页面
  2. 弹出红包的页面
  3. 抢完红包的页面

我们要分析它的包名、层次结构、关键文本信息View id等。

实现自动抢红包

在onAccessibilityEvent方法中,要根据我们分析的内容进行相应的过滤,来获取或者响应我们的内容。

首先,我们可以通过过滤包名将其他软件过滤在外:

image.png

这里我们说明一下getRootInActiveWindow()和onAccessibilityEvent(AccessibilityEvent event)中的event.getSource(),他们都是返回AccessibilityNodeInfo但是区别是有的

  • getRootInActiveWindow():整个窗口的对象
  • event.getSource:得到的是被点击的单体对象

很明显我们应该使用前者。另外,我们可以通过调用AccessibilityNodeInfo中的findAccessibilityNodeInfosByText和findAccessibilityNodeInfosByViewId,分别用来根据子View的文字和Id来查询相应的AccessibilityNodeInfo,并且它的performAction方法可以模拟很多“动作”就像是点击、长按等,当然这都是在该View是可以被点击的前提下生效。有了这些,实现自动抢红包插件就不困难了.

收到红包的页面

收到红包时,对方发的红包会有显示“领取红包”的字样,自己的发送的红包会有“查看红包”的字样,根据这一点,我们找到对应可以点击的View。

image.png

通过实验我们发现是通过点击一个LinearLayout实现的弹出红包的功能.

image.png image.png

弹出红包页面

同样的道理,我们用上面的方法继续找到了对应点击的位置。

image.png

但是需要特别注意的是,在真正执行抢红包动作时,尽量延迟几百毫秒,如果微信自查出来,这很危险!

抢完红包的页面

抢完红包的页面跟其他不同的是它在单独的一个Activity,需要使用到performGlobalAction来模拟全局返回键。

image.png

通知栏点击抢红包

如果当前不在微信页面怎么办,小意思,我们也有办法,当你开启微信群的通知时,当红包来时将会触发 AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED,所以此时可以通过它过滤是否是红包来了,完成通知栏的点击然后进行后面的抢红包操作。

image.png image.png

至此,自动抢红包插件的主要实现就介绍完毕。详情请看GitHub代码.

4 其他

有些时候我们需要模拟点击屏幕中的某个位置,而不局限于某个View,这里我从网上找到了一个方法放在这里,方便以后查阅:

image.png

水平有限,内容粗略,敬请谅解

欢迎关注我的微信公众号:

敲行代码再睡觉

点击阅读原文查看GitHub项目