浅谈Android手机的抢红包插件

前语

最近,Android手机上的手机管家更新了新版本,提供了红包闹钟功能,只要有微信红包或者QQ红包,就会自动提醒。恰逢最近又在做UI自动化的工作,使用到UI Automator框架。几行代码,就可以让手机自动完成某些操作,很有意思,今天就来扒一扒这背后的原理。

UI Automator

传统的手工测试,我们需要点击一些控件元素,来查看输出的结果是否符合预期。比如在登录界面,输入正确的用户名和密码,点击登录按钮后,就可以正常登录。

如果这些操作,每一次都需要手工执行的话,是需要大量的人力成本的,比如手机QQ安卓端, 手工用例有上万条。所以就需要大力推广自动化测试。

UI自动化作为测试金字塔的最顶层,承担了端到端的需求回归与灰度验证任务,其重要性不言而喻。

UI Automator作为一款Google谷歌推出的,用于UI自动化测试的工具,有着优秀的API与社区文档。也是目前主流的Android自动化测试框架。它提供了一系列用于获取手机上页面控件元素和操作元素的方法,非常方便。

注意:UI Automator测试框架是基于instrumentation的API,运行在Android JunitRunner 之上,同时UI Automator Test只运行在 Android 4.3(API level 18)以上版本。

从一次抢红包说起

想想我们平时抢红包的流程是什么样的呢?

假如你现在正在刷剧,这时候通知栏提醒你微信有红包了,于是你点击通知栏的消息,进入了微信页面,找到了红包,再点击拆红包的按钮,小手一抖,几毛到手。

这么一想,其实这些步骤完全是一个体力活,要是有个机器人能自动抢就好了!

这个机器人的背后就是AccessibilityService,当然它的具体作用我们稍后再讲。

按照我们的现有的逻辑,自动抢红包大致分为以下几个步骤:

  1. 识别获取通知栏的微信红包的通知事件
  2. 点击通知栏的消息
  3. 获取红包的消息
  4. 点击按钮拆红包

这里面最最重要的两个步骤就是识别,操作。接下来我们侃侃这两步。

怎么识别页面控件元素?

首先,我们先来认识一下UI Automator viewer这个工具,位于<android-sdk>/tools/bin目录下,他可以很方便地扫描和分析 Android 设备上当前显示的界面组件,展示一棵完整的控件树,与某一个叶子节点(控件元素)的属性。

从上图我们可以看到,页面的一个登录按钮元素,有自己的text属性,resource-id属性,content-desc属性等等。

UI Automator中,存在uiDevice类,可以通过findObject方法,查看到这些控件元素。

UiObject2 login_btn = uiDevice.findObject(By.desc("登录"));

现在我们深入findObject方法,

    public UiObject2 findObject(BySelector selector) {
        // 这里返回匹配选择器的第一个节点,如果没有找到匹配的话,就返回null
        AccessibilityNodeInfo node = ByMatcher.findMatch(this, selector, getWindowRoots());
        return node != null ? new UiObject2(this, selector, node) : null;
    }

可以看到,这里传入了一个选择器selector,然后在ByMatcherfindMatch方法中查询,如果找到了,就返回一个AccessibilityNodeInfo的node,如果没有找到就返回null。

首先看ByMatcher是什么东东?这是一个实用工具类,通过它的方法,我们可以在一个树形结构中搜索到匹配selector的节点。

findMatch方法很简单,就是一个从根节点开始搜索的树型搜索方法,不用多说。

AccessibilityNodeInfo是什么呢?这相当于一个节点,在AccessibilityService的角度来看,这就是一个可访问到的控件节点。

那这么来看,findMatch的第三个参数,就是传入的控件树的根节点了吗?我们深入看一下这里的getWindowRoots方法的关键代码,

 /** 这里返回活动窗口容器的root节点的列表 */
    AccessibilityNodeInfo[] getWindowRoots() {
        // 等待线程空闲后再执行
        waitForIdle();
        // 初始化一个root节点的集合
        Set<AccessibilityNodeInfo> roots = new HashSet();

        // 通过UiAutomation获取当前最底部的根窗口容器的root节点
        AccessibilityNodeInfo activeRoot = getUiAutomation().getRootInActiveWindow();  // 这里使用UiAutomation的方法
        if (activeRoot != null) {
            roots.add(activeRoot);
        }

        // 多窗口容器的搜索
        if (UiDevice.API_LEVEL_ACTUAL >= Build.VERSION_CODES.LOLLIPOP) {
            for (AccessibilityWindowInfo window : getUiAutomation().getWindows()) { // 这里使用UiAutomation的方法
                AccessibilityNodeInfo root = window.getRoot();
                …………
                roots.add(root);
            }
        }
        return roots.toArray(new AccessibilityNodeInfo[roots.size()]);
    }

这里要提一下,UiAutomation是Google在Android4.3的时候,发布的一个自动化框架,它提供了与系统底层交互的能力。

再往下,我们看看UiAutomationgetWindows方法的关键代码:

    public List<AccessibilityWindowInfo> getWindows() {
      ……
        return AccessibilityInteractionClient.getInstance()
                .getWindows(connectionId);
    }

这里获取了AccessibilityInteractionClient的实例,然后返回了client的getWindows方法结果。然后再看一下这个getWindows方法的关键代码,

    public List<AccessibilityWindowInfo> getWindows(int connectionId) {
            ……
            IAccessibilityServiceConnection connection = getConnection(connectionId);
            if (connection != null) {
                // 首先去查询缓存,如果缓存是有的,直接返回
                List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows();
                   ……
                    return windows;
                }
                ……
                 // 如果上面的缓存不存在,就调用connection.getWindows方法
                 windows = connection.getWindows();
                 ……
                if (windows != null) {
                    // 把上面获取到的新的windows放置缓存,并返回
                    sAccessibilityCache.setWindows(windows);
                    return windows;
                }
            }
             ……
    }

IAccessibilityServiceConnection开始,在IDE中就开始提示Cannot resolve symbol 'IAccessibilityServiceConnection',无法再跳转追踪了。这是因为这个文件属于aidl文件,这是Android中用于跨进程通信的接口文件,其具体源码可以在GoogleSource上面看到,有兴趣的同学可以去看一下:IAccessibilityServiceConnection.aidl。 这说明,到这里,UI Automation进程开始了与AccessibilityService进程的通信。我们把当前的程序可以当做是客户端,那么Android系统服务就是服务端,从这里开始,真正深入到Android系统的核心。在下面,就是Android Native的Library库。

这里,我们可以用时序图总结一下:

怎么操作页面页面元素?

我们现在已经知道了UI Automator是怎么识别控件的,那怎么操作控件元素呢?比如实现控件的自动点击。

我们还是从源码开始入手。比如一个控件元素的点击动作,在UiObject2类中,关键代码如下:

    public void click() {
        mGestureController.performGesture(mGestures.click(getVisibleCenter()));
    }

首先,getVisibleCenter方法可以根据控件节点信息,也就是上面提到的AccessibilityNodeInfo,获取到这个控件节点的中心坐标点。然后把这个坐标点传给mGestureclick方法,这里是为了封装点击动作,最后交给mGestureController对象的performGesture方法去实施这个点击动作。

对于mGestureclick方法,这个mGesture是一个构造工厂,它的click方法直接生成了一个PointerGesture对象,这个对象表示的是执行手势操作时的动作。比如手势的开始坐标点,结束坐标点,持续时间,移动方向,速度等等。

重点看一下mGestureController对象的performGesture方法,其关键代码如下:

public void performGesture(PointerGesture ... gestures) {
          …………
         // 执行传入的手势操作动作
        MotionEvent event;   // 这个是关于运动事件
        for (……) {
                 …………
               // 初始化运动事件,并调用UI Automation的injectInputEvent注入事件,异步执行
                event = getMotionEvent(……);
                getDevice().getUiAutomation().injectInputEvent(event, true);
                …………
            }
          …………
        }
}

这里可以看到事件的注入,也是通过UI Automation来完成的。看一下injectInputEvent方法的关键代码,

    public boolean injectInputEvent(InputEvent event, boolean sync) {
        …………
        // 异步执行,这段代码之前有关于锁的操作
        return mUiAutomationConnection.injectInputEvent(event, sync);
        …………
    }

我们发现也是通过一个connection来执行操作的,这个connection对象对应的IUiAutomationConnection类,也属于一个aidl文件。

这里也放一个时序图,

AccessibilityService

AccessibilityService根据官方说明,是指开发者通过增加类似contentDescription的属性,从而在不修改代码的情况下,让残障人士能够获得使用体验的优化,大家可以打开AccessibilityService来试一下,点击区域,可以有语音或者触摸的提示,帮助残障人士使用App。

当然,现在国内,AccessibilityService已经被玩儿坏了,越来越多的App借用AccessibilityService来实现了一些其它功能,甚至是灰色产品。

在国内,通过AccessibilityService实现的功能包括免Root自动安装,自动抢红包,微信消息自动回复等等黑科技。

当然也有一些恶意功能,比如软件防卸载。当用户想要卸载你的App的时候,一般会来到设置界面,找到你的App然后选择卸载,那么如果我们监控这个页面,如果发现是自己的App,就直接退出,这样不就无法卸载了吗?是的,简简单单,但是背后的恶意却让人心寒。

使用AccessibilityService做自动化的步骤

大家看了上面的分析,可能对自动化有了一点兴趣,其实归纳起来,步骤很简单:

  1. 分析整个操作流程,拆解成关于每个控件的识别与操作。
  2. 利用uiautomatorviewer等工具,查看对应UI控件的属性,进行唯一性识别
  3. 编写代码,查找到元素后,进行点击等操作
  4. 兼容性处理

结语

大家经常说“面试造火箭,工作拧螺丝”。其实大家平时工作可能都是“拧拧螺丝”,但是站在个人职业发展角度来看,是不可取的。只有不断挖深自己的技术护城河,才能提高个人的不可替代性。在“拧螺丝”的时候,我们不妨抬头看看,整个“火箭”是的构造。

以上就是浅谈Android手机的抢红包插件的详细内容,更多关于Android抢红包插件的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android中微信抢红包插件原理解析及开发思路

    一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导致了.或许是网络的原因,而且这个也是最大的原因.但是其他的不可忽略的因素也是要考虑到进去的,比如在手机充电锁屏的时候,我们并不知道有人已经开始发红包了,那么这时候也是让我们丧失了一大批红包的原因.那么关于网络的问题,我们开发者可能用相关技术无法解决(当然在Google和Facebook看来的话,他们

  • Android微信自动抢红包插件优化和实现

    又是兴趣系列 网上有很多自动强红包的例子和代码,笔者也是做了一些优化. 先说说自己的两个个优势 1.可以在聊天界面自动强不依赖于通知栏推送 2.可以在屏幕熄灭的时候的时候点亮屏幕自动抢(目前只测过flyme) 先上图: 代码传送门: https://github.com/AndroidMsky/WXhongbao 欢迎点星星~ 原理: 通过AccessibilityService监听到状态栏通知,进行模拟点击,获取屏幕中view节点为领取红包的list并且点击最后一个. 如果不通过状态栏通知,通

  • Android抢红包插件实现原理浅析

    抢红包,先看效果图~ 实现自动抢红包,解决问题有两点: 一:如何实时监听发红包的事件 二:如何在红包到来的时候自动进入页面并自动点击红包 一.如何获取红包到来的事件 为了获取红包到来状态栏的变化,我们要用到一个类:Accessibility 许多Android使用者因为各种情况导致他们要以不同的方式与手机交互. 这包括了有些用户由于视力上,身体上,年龄上的问题致使他们不能看完整的屏幕或者使用触屏,也包括了无法很好接收到语音信息和提示的听力能力比较弱的用户. Android提供了Accessibi

  • Android实现QQ抢红包插件

    又想到快要过年了,到时候还不知道群里要发好多红包,所以我将之前在网上宕的一份微信抢红包的代码修改了一下,实现了QQ抢红包!可以支持抢QQ拼手气红包,普通红包,口令红包,现在再也不怕20年单身手速的人跟我抢红包了! 先看测试效果图: 1.抢QQ口令红包  可以看见,只要红包一发出,自动填写口令并发出,帮你将红包抢到手! 2.抢QQ拼手气红包 拼手气红包也是一样,只要红包一发出,自动帮你把红包抢到手,是不是很爽的感觉? 3.抢QQ好友发送的红包 只要好友或者群里的人把红包一发出,就会第一时间让你抢到

  • Android AccessibilityService实现微信抢红包插件

    在你的手机更多设置或者高级设置中,我们会发现有个无障碍的功能,很多人不知道这个功能具体是干嘛的,其实这个功能是为了增强用户界面以帮助残障人士,或者可能暂时无法与设备充分交互的人们 它的具体实现是通过AccessibilityService服务运行在后台中,通过AccessibilityEvent接收指定事件的回调.这样的事件表示用户在界面中的一些状态转换,例如:焦点改变了,一个按钮被点击,等等.这样的服务可以选择请求活动窗口的内容的能力.简单的说AccessibilityService就是一个后

  • 浅谈Android手机的抢红包插件

    前语 最近,Android手机上的手机管家更新了新版本,提供了红包闹钟功能,只要有微信红包或者QQ红包,就会自动提醒.恰逢最近又在做UI自动化的工作,使用到UI Automator框架.几行代码,就可以让手机自动完成某些操作,很有意思,今天就来扒一扒这背后的原理. UI Automator 传统的手工测试,我们需要点击一些控件元素,来查看输出的结果是否符合预期.比如在登录界面,输入正确的用户名和密码,点击登录按钮后,就可以正常登录. 如果这些操作,每一次都需要手工执行的话,是需要大量的人力成本的

  • 浅谈Android手机联系人开发之增删查改功能

    最近在做手机联系人的功能模块的时候,遇到了很多的坑,在网上搜索的有一些所谓的最全的手机联系人开发的介绍还存在一些bug,所以我把我最近的项目心得和方法写下来,既能帮助大家减少了解android开发手机联系人的门槛,好,废话少说,接下来直奔主题. 一.深入浅出手机联系人的前奏(小米手机的data表跟模拟器的data表不一样) 1.手机联系人主要是对contacts2.db数据库表的操纵,这个数据库中有三个表是比较重要的,分别是data,raw_contacts,mimetyps这三个表.在下面的增

  • 浅谈Android插件化

    目录 一.认识插件化 1.1 插件化起源 1.2 插件化优点 1.3 与组件化的区别 二.插件化的技术难点 三.ClassLoader Injection 3.1 java 中的 ClassLoader 3.2 android 中的 ClassLoader 3.3 双亲委派机制 3.4 如何加载插件中的类 3.5 执行插件类的方法 四.Runtime Container 4.1 为什么没有注册的 Activity 不能和系统交互 4.2 运行时容器技术 4.3 字节码替换 五.Resource

  • 浅谈android获取设备唯一标识完美解决方案

    本文介绍了浅谈android获取设备唯一标识完美解决方案,分享给大家,具体如下: /** * deviceID的组成为:渠道标志+识别符来源标志+hash后的终端识别符 * * 渠道标志为: * 1,andriod(a) * * 识别符来源标志: * 1, wifi mac地址(wifi): * 2, IMEI(imei): * 3, 序列号(sn): * 4, id:随机码.若前面的都取不到时,则随机生成一个随机码,需要缓存. * * @param context * @return */ p

  • 浅谈Android Studio 3.0 工具新特性的使用 Android Profiler 、Device File Explorer

    前言: 其实 studio3.0的工具大家也已经使用过一段时间了,自己呢,就是从bate版开始使用的,我觉得比较好用的几个地方.就几个,可能还没用到其他的精髓. 但我觉的这个两个功能对我是比较实用的.好那么下面就给大家介绍一下吧. 正文: 话不多说咱们直接上图吧.(个人比较喜欢看图说话) 第一个(Android Profiler)我要介绍的就是这个了.(先看一下效果"震撼一下") (图-1) (图-2) (图-3) (厉害不厉害,牛逼不牛逼)那么我们怎么来操作这个工具呢,来咱们接着看图

  • 浅谈Android View绘制三大流程探索及常见问题

    View绘制的三大流程,指的是measure(测量).layout(布局).draw(绘制) measure负责确定View的测量宽/高,也就是该View需要占用屏幕的大小,确定完View需要占用的屏幕大小后,就会通过layout确定View的最终宽/高和四个顶点在手机界面上的位置,等通过measure和layout过程确定了View的宽高和要显示的位置后,就会执行draw绘制View的内容到手机屏幕上. 在详细介绍这三大流程之前,需要简单了解一下ViewRootImpl,View绘制的三大步骤

  • 浅谈Android中Service的注册方式及使用

    Service通常总是称之为"后台服务",其中"后台"一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件: 1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的): 2.具有较长时间的运行特性. 1.Service AndroidManifest.xml 声明 一般而言,从Service的启动方式上

  • 浅谈android获取存储目录(路径)的几种方式和注意事项

    通常, 我们创建文件/目录, 或者存储图片什么的, 我们都需要拿到手机的存储路径, 现在我们就来看一下获取手机存储路径的几种方式(作为工具类方法调用即可): 第一种: 获取 /storage/emulated/0 public static boolean sdCardIsAvailable() { //首先判断外部存储是否可用 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { File

  • 浅谈Android Studio3.6 更新功能

    前言 下载google CodeLab的程序时,提示要更新3.6版本才能运行程序,于是更新了一下,看看有什么新功能. 界面设计工具 这次更新了一些设计工具,比如Layout Editor 和 Resource Manager. 现在,在XML或设计工具的颜色选择器中,Android Studio会在您的应用程序中填充颜色资源,以便您快速选择和替换颜色资源值. 拆分视图并放大设计编辑器 设计编辑器(例如,布局编辑器和导航编辑器)现在提供一个拆分视图,使您可以同时查看UI的"设计"视图和&

  • 浅谈android中数据库的拷贝

    SQLiteDatabase不支持直接从assets读取文件,所以要提前拷贝数据库.在读取数据库时,先在项目中建立assets文件夹用于存放外部文件,将数据库文件拷到该目录下. 代码方法: /** * 拷贝数据库至file文件夹下 * @param dbName 数据库名称 */ private void initAddressDB(String dbName) { //1,在files文件夹下创建同名dbName数据库文件过程 File files=getFilesDir();//获取/dat

随机推荐