0%

抢红包插件分析以及应用

临近春节,群里的红包又多了(也许仅仅是群多了),由于流行了各种抢红包插件,红包基本是秒没的节奏。在好奇心的驱使下研究了一下抢红包插件的原理,发现既简单又很有意思。还能用来干些其他羞羞的事情😉。。

参考Github项目源码 微信抢红包插件

基本原理

在没有看Github上的实现的时候,我天真地以为这种插件的原理类似于PC平台上的按键精灵(Android版也有),或者一些测试化工具。这一类软件实现起来应当比较复杂,Too Yang Too Simple。Android已经提供了完备的系统。

AccessibilityService 服务(Service),初衷是用于辅助服务,总之它的功能是根据用户的一些操作给用户相应的提示,如给残疾人自动读出选择的文字。

我们需要做的是

  1. 继承AccessibilityService,写自定义的辅助服务
  2. 当用户App的界面发送变化时,会触发Service的相关回调,在该回调中可以获取当前界面中的UI界面元素节点(不是view本身,是它的一个映射而且可能不是一一映射)。
  3. 根据关键字/元素id查找需要的view,处理之,如模拟点击。
  4. done

源码分析

学习AccessibilityService

官方文档两篇文章通读之 Android Train && Android API指南
中文可以学习的文章 Android中微信抢红包插件原理解析和开发实现

关键API

  • Service配置
1
2
3
4
5
6
7
8
9
10
<!--自定义的服务和指定配置文件res/xml/accessible_service_config.xml-->
<service
android:name=".HongbaoService"
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/accessible_service_config"/>
</service>
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_name"
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackAllMask"
android:packageNames="com.tencent.mm"
android:notificationTimeout="10"
android:accessibilityFlags=""
android:canRetrieveWindowContent="true"/>

android:packageNames=”com.tencent.mm” 指定要监听的程序的包名
android:canRetrieveWindowContent=”true” 可以获取具体的内容
android:accessibilityEventTypes 监听的事件
android:accessibilityFeedbackType=”feedbackAllMask” 设置反馈事件(如振动一下提示用户),这里是屏蔽所有反馈。

  • Servive回调
1
2
3
public void onAccessibilityEvent(AccessibilityEvent event) {
// 回调
}
  • 节点查找
1
2
3
4
5
6
// 获取所有阶段
AccessibilityNodeInfo nodeInfo = event.getSource();
// 查找所有有"领取红包"的View
List<AccessibilityNodeInfo> node1 = nodeInfo.findAccessibilityNodeInfosByText("领取红包");
// 查找所有id是com.tencent.mm:id/ar6
List<AccessibilityNodeInfo> node2 = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ar6");

注:可以通过DDMS里的Dump View Hierarchy For UI Automator 分析UI结构来获取id

  • 出发操作
1
2
3
4
// 对某个节点操作
cellNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
// 按下手机的后退键
performGlobalAction(GLOBAL_ACTION_BACK);
  • 启动Accessibility的系统设置界面,需要用户手动打开服务
1
2
3
Intent intent =
new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);

几个注意点

  • AccessibilityService 建议在Android4.0以及以上版本中使用,也有support_v4 向下兼容。
  • Services配置可以通过xml配置,也可以通过代码配置
  • 不同系统的Api可能结果不同(如API16),如查找不到一些元素

In Android 4.1 (API Level 16) and higher, the getSource() method, as well as AccessibilityNodeInfo.getChild() and getParent(), return only view objects that are considered important for accessibility (views that draw content or respond to user actions). If your service requires all views, it can request them by setting the flags member of the service’s AccessibilityServiceInfo instance to FLAG_INCLUDE_NOT_IMPORTANT_VIEWS

  • AccessibilityNode可能有一个实例池的设计。获取当前窗体节点树的时候,从一个可重用的实例池中获取一个辅助节点信息 (AccessibilityNodeInfo)实例。在接下来的获取时,仍然从实例池中获取节点实例,这时可能会重用之前的实例。这样的设计是有好处的,可以防止每次返回都创建大量的实例,影响性能。AccessibilityNodeProvider的源码表明了这样的设计。

抢红包

微信抢红包插件的dev分支的逻辑比较复杂(参考工程的README文件,致力于区分各种状态和不重复抢相同红包),实测不稳定,stable分支逻辑比较简单也较稳定。具体代码就不说了。

Do Something

抢红包插件网上有很多实现,我所见的都是用AccessibilityService来做的。用这个Service的确可以做一些有趣的事情,打算在后续阶段用这个原理写一个微信自动聊天程序,当然是要建立在自己搭建的框架之上的。

欢迎关注我的其它发布渠道