当前位置:首页 > 技术文章 > 正文内容

Android中使用ASPECTJ进行用户操作路径跟踪与日志搜集

u3blog2年前 (2022-10-08)技术文章594

编写初衷

在Android App开发中,出现了bug和崩溃测试们就会提着手机上门,然后开发一顿操作,bug消失了,测试们又只有进行大量的操作来复现。

这样的情况想必大家都遇到过,更极端的是线上出现了bug,虽然可以设置崩溃日志上传来收集崩溃日志,但是用户是怎么操作的,我们也只能靠猜

为什么不能有一个工具,记录下最近打开了什么界面,点击了哪些按钮,并且记录到本地,方便开发们查看呢?于是笔者有了写这个工具的想法。

我们来缕一缕:我们的工具要实现的几个功能

  1. 记录activity的打开和关闭情况
  2. 记录fragment的打开和关闭情况
  3. 记录控件的点击情况
  4. 把这些日志存放到本地,方便上传和查阅

用什么技术实现

有了目标,我们就可以考虑怎样实现了,大概有以下几种方式实现操作收集

这种技术有个名称,叫做埋点,因为我们就像埋地雷一样在指定位置设置代码,当触发的时候打日志并收集

  1. 人工手动埋点
  2. 使用特殊控件,原理与1类似,不过工作转移给了写控件的人
  3. 使用aop框架进行自动化埋点,比如aspectj或者asm
  4. AccessibilityService配合ContentDescription进行埋点

选择哪项技术呢,我们逐项分析

  1. 虽然最简单,但是工作量大,容错错埋漏埋,放弃
  2. 工作量巨大,使用者学习成本高,放弃
  3. 使用简单,通用,考虑使用
  4. 需要开发时添加ContentDescription并且某些机型无法开启AccessibilityService相关设置,有局限性

综合考虑之后,我们选择了使用aop的方式埋点,我们现在有两个选择,aspectj或者asm,但是有于asm过于灵活学习和使用均有一定门槛,所以我们选择简单易用的aspectj

基本思路

通过对aspectj的学习,我们发现可以对onclick方法以及生命周期方法进行切点设置,至于什么是切点,将会在后续部分解释

日志方面,我们采用了开源项目ZLog进行记录,该框架实现了日志写到文件,以及对文件的数量和大小管理功能,比较方便

对于最后一项,由于使用itembinding等框架的时候会遇到捕获不到具体类的情况,所以按需要进行捕捉

关于Aspectj

这个工具最关键的还是怎样使用aspectj去做埋点,关于aspectj的使用网上有很多例子,这里就不赘述了,下面贴出一个简单的使用文件,大家配合注解看一下,如果还是不太明白建议先去搜一些基本使用的帖子

@Aspect//标注这个类是一个aspectj需要处理的类
class AspectJTest {
    @Pointcut("execution(void _internalCallbackOnClick(..))")//切点,检测返回值为void的_internalCallbackOnClick方法
    fun onBindingClick() {
    }

    @Around("onBindingClick()")//在合适的时机对切点进行处理
    @Throws(Throwable::class)
    fun onClickMethodBinding(joinPoint: ProceedingJoinPoint) {
        val args = joinPoint.args//获取方法参数
        if (args.size >= 1 && args[1] is View) {
            val view = args[1] as View//获取view
            val id = view.id
            //处理该view或者打印日志
        }
        joinPoint.proceed() //执行原来的代码
    }
    }

需要解决的问题

虽然看起来aspectj用起来很简单,但还是有一些问题需要我们处理

  1. 怎样获取点击事件的控件id和它所在的类名
  2. 怎么获取在list中的点击事件,并获取它的位置信息
    关于第一点,我们普通使用setOnClick设置是可以拿到的,但是当使用databinding等技术的时候情况就比较复杂了,我们如果使用以下代码,就会获取到生成类里的一个onclick文件,根本不知道哪个页面的控件被点击了
    @Around("onClick()")
     @Throws(Throwable::class)
     fun onClickMethodAround(joinPoint: ProceedingJoinPoint) {
         //获取点击事件view对象及名称,可以对不同按钮的点击事件进行统计
         val target = joinPoint.target
         var className = ""
         if (target != null) {
             className = target.javaClass.name
             if (className.contains("$")) {
                 className = className.split("\\$").toTypedArray()[0]
             }
             if (className.contains("_ViewBinding")) {
                 className = className.split("_ViewBinding").toTypedArray()[0]
             }
         }//看似可以获取,但是实际使用itembinding的时候只能拿到生成的onclick文件名,没有其他信息
         joinPoint.proceed() //执行原来的代码
     }

要处理这个问题,我们需要监听生成类中的点击事件,在笔者这里,这个事件方法名叫做_internalCallbackOnClick,我们添加一个对它的切点就可以了

对于问题2,我们可以通过获取view的父view,并判断它的类型,再通过强转来解决,代码如下

  val view = args[0] as View
                var index = -1
                if (view.parent is RecyclerView) {
                    index = (view.parent as RecyclerView).getChildPosition(view)
                }

输出

当完成了埋点之后,我们就可以把日志输出到文件里了,这里我使用了一个叫ZLog的库,不过由于有一些年头了,我直接复制了文件到项目中。如果大家有兴趣可以去看看ZLog代码仓库并点个star

总结与完全代码

解决了上面的问题,我们就可以检测到想要的信息并保存了,以后测试来找我们的时候排查bug又多了一点点线索,线上用户报bug的时候也不用胡乱猜测了,是不是感觉很有用呢?(可能并没有

如果想看完全的代码,可以到github上的这里来看看如果能顺便点个star就再好不过了,如果有任何问题,也可以留言讨论

扫描二维码推送至手机访问。

版权声明:本文由u3blog发布,如需转载请注明出处。

本文链接:https://u3blog.xyz/?id=698

分享给朋友:

“Android中使用ASPECTJ进行用户操作路径跟踪与日志搜集” 的相关文章

开源数据库Postgresql安装/卸载总结

What Postgresql一个开源数据库,类似mysql,由于mysql被收购了,这个数据库正被越来越多的使用 怎么安装?安装非常简单,但是安装过后的初始化还是有点麻烦,具体可以看这篇文章为什么要卸载?安装好之后,如果你很倒霉的话,会遇到postgresql服务怎么都启动不了,输入psql指令显...

AndroidStudio插件开发——RemoveButterKnife从构思到实现

AndroidStudio插件开发——RemoveButterKnife从构思到实现

ReomveButterKnife插件这是一个用于移除代码中对ButterKnife使用的AS插件,接下来我们将从头开始讲讲AS插件开发和这个插件的开发过程地址是<a href="https://github.com/u3shadow/RemoveButterKnife"...

项目的改造——RemoveButterKnife插件代码的重构

项目的改造——RemoveButterKnife插件代码的重构

前言这篇文章记述了我的插件RemoveButterKnife的代码改进过程以及思路,关于插件,各位可以看RemoveButterKnife代码库,关于文章,可以看构思到实现RemoveButterKnife 原因近期想给原来的插件RemoveButterKnife加入一些新的功能,发现以前的代码没...

项目的升级-给RemoveButterKnife插件增加新功能

项目的升级-给RemoveButterKnife插件增加新功能

前言经过项目的初步编写和进一步改造,RemoveButterKnife插件终于也有模有样了,但是,功能上仅仅支持Activity/Fragment的BindView注解。 关于编写和优化的过程可以看下面两篇文章项目构造RemoveButterKnife 项目改进-重构RemoveButterKn...

Android测试体系-在MVVM架构中如何测试Model层与ViewModel层

背景此文章是对于google code lab中《Introduction to Test Double and Dependence injection》 与 《Testing Basics》的总结,本篇主要讲述如何在mvvm架构的android项目中对Model层以及ViewModel层进行测试...

使用Databinding为Recyclerview使用同一个ViewHolder加载不同Item

提示:在阅读本篇文章前,你最好对android databinding有一定了解,本文使用的代码均为kotlin,但是不用担心,都很简单 最近在写项目的时候使用了databinding技术,突发奇想,databinding是不是也能应用于recyclerview中,让加载多个不同的item更简单呢...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。