Android 黑科技 |Gradle Plugin使用场景

2020-10-15 10:20:03 浏览数 (1)

一直想写一些关于安卓plugin的应用场景。只要想法够胆子大,这个能做很多你意想不到的优化点。

Apm 监控方法耗时

先介绍两个项目

  1. 滴滴的哆啦A梦调试组件,里面有个工具叫性能监控,他可以调试出项目内耗时的方法,之后将耗时方法打印出来。
  2. 腾讯的matrix,这个项目是拿来做项目的性能监控的,其中也有一个监控方法耗时的。 在没了解这些项目之前,我对这些技术吧,只能佩服三连。但是了解了大体的实现之后只能说plugin transform 真香。
代码语言:javascript复制
  dependencies {
      classpath ("com.tencent.matrix:matrix-gradle-plugin:${MATRIX_VERSION}") { changing = true }
  }
  
  apply plugin: 'com.tencent.matrix-plugin'
   matrix {
    trace {
        enable = true	//if you don't want to use trace canary, set false
        baseMethodMapFile = "${project.buildDir}/matrix_output/Debug.methodmap"
        blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt"
    }
  }
代码语言:javascript复制
        classpath 'com.didichuxing.doraemonkit:doraemonkit-plugin:3.1.5'
        apply plugin: 'com.didi.dokit'

观察两个项目的接入文档,其实都发现了他们内部含有一个gradle插件。

滴滴其实前一阵子正好分享了他们的技术文章描述了下关于耗时监控的,开个传送门 滴滴DoKit Android核心原理揭秘之函数耗时, 简单的说就是在项目的方法头和方法尾插入了一段代码块,然后通过这个代码块去监控函数耗时。

Matrix的函数耗时呢,其实我反编译了下我们的项目,发现在所有的方法头和方法尾都被插入了监控耗时,但是matrix毕竟是一个专业的做apm的项目,所以他在插入代码的时候会做一些类类型的判断逻辑,比如application和activity的插入的逻辑可能有些许不同。

动态注册

各位写过路由组件的话肯定会有一个问题,apt触发AbstractProcessor的时候,javapoet只可以动态生成新的代码,没办法在已经存在的类上做修改。如果是多模块的项目的情况下,动态注册的问题就是一个很棘手的问题,你需要把所有模块的初始化操作都调用一次,才能完成你的路由表的构建。

ARouter在构建的早期版本,使用的是ClassUtils的方式,通过ClassLoader去搜索包名下的所有的类的方式,然后通过反射调用去完成的项目初始化。这个当你的项目足够大的情况下,耗时会是指数型上升。

之后有个老哥给阿里的ARouter提了个MR,以及如何优化初始化过程。将这个搜索包名的过程从运行时调整到了编译时。

AutoRegister也就是这个项目,通过transform,然后在编译过程中,搜集好所有实现了特定接口的class,然后将他们插入到一个注册的类上去。最后吧Arouter项目并没有使用AutoRegister,他们自己写了个plugin插件,把autoregister的代码做了一次阉割。还有美团的wmrouter也是一样的机制。

顺便吐槽下,貌似ARouter和wmrouter两个plugin都没有实现增量编译,然后把这个速度就真的很微妙。

无痕埋点

开发人员其实都知道,埋点这个东西又繁琐又容易出bug,有没有什么很好的方案可以一次性解决大部分埋点的问题呢,后续就不需要开发介入了。

我去听了网易的一个无痕埋点的讲座,思路也是基于transform的方式,将所有实现了View.OnClickListner接口的实现类全部进行一次修改,在onClick(View v)的方法头插入一段埋点的代码,然后内部通过反射的机制,获取到当前class的一些字段内容然后上报。

当然我自己之前的项目也有类似的需求,所以我也自己撸了一个。无痕埋点 还有就是我之前写的双击优化也是同样的机制,我就不多说了。

Dex包体积优化

如果各位最近有去过面试的话,相信这个问题或多或少可能被问到过,本文切入的思路可能会有些不同,我们讲dex包体积优化方面的。

对于dex来说,.class文件越小自然包体积越小,这个是大家都知道的一个现象。我最近观察了下头条开源的byteX 。发现了好久个关于包体积优化的plugin,getter-setter-inline-plugin,access-inline-plugin,shrink-r-plugin,const-inline-plugin。这几个仓库都是和dex体积优化相关的。

  1. shrink-r-plugin 先将R文件内的id值全部提取出来,然后搜索所有.class,当发现到R.xxx.xxx的引用直接替换为值,最后删除多余的R
  2. getter-setter-inline-plugin get set 函数内联
  3. access-inline-plugin 内联access$方法
  4. const-inline-plugin 常量值内联

个人看法头条在包体积优化的路上走的还是非常远的,而且深度也非常可以。

类替换

项目内有时候会直接使用一些系统提供的api,但是其实内部是可能出现一些异常情况的。举个例子intent取值的时候如果类型转换出错是有可能直接崩溃的。特别是在一些路由跳转的情况下,将url params的参数反序列化之后。

这个时候也可以通过transform 对当前类进行方法调用进行一次修改,替换成我们包装过的一个异常处理过的类,这样就可以保证一些奇特的异常场景,无法处理的情况。

还有就是如果你要删除你项目内的Log输出,你的历史代码又特别多,这个时候咋办。自己定义一个lint规则搜索,删除工作量太大。你也可以用transform去改,在项目打包时检测是否存在特定的类调用,如果调用则不去写入。

资源文件体积压缩

AndResGuard这个项目应该有些人都听说过,是一个资源文件混淆的库,微信团队写的。也是做包体积优化的。

但是这个仓库和上面的还是有很大差异的,上面的大部分是基于Transform去写的,而这个仓库则是添加了个task 任务,去做资源文件的混淆。

总结

不知道各位老哥看了上面这些项目之后有没有一些自己的看法,可以一起讨论一下,一起探讨下宇宙的边界。

0 人点赞