牛逼的Transform Plus | Transform进阶教程

代码 代码 1596 人阅读 | 0 人回复

<
媒介

之前写过一篇文章引见了下闭于Transform删量怎样编写。此次我念睁开道些此外。
先扔出几个偶奇异怪的成绩。

  • 假如要写R文件内乱联的状况下,列位年夜佬会咋操作,能够会碰着甚么成绩?
  • 假如Transform过期没有让利用了,那末该当用那种方法笼统会比较好。
最初便是一些我近来玩的一些简朴asm相干的工具吧。
  AndroidAutoTrack
开端拆逼了

假如要正在R文件内乱联的状况下,能够会碰着甚么成绩?
  正在安卓agp 4.1.0 版本上 R8曾经做了那部门的内乱联操作了,完整没有需求我们再来写那么个转换
由于正在Transform操作过程当中,我们是经由过程文件途径的情势来会见一个个class文件的,这类状况下便没法确保会见的能否是有序战有语法的。
由于我们起首要与到的是R文件,然后把R文件的内乱容搜集起去,以后再来一切有利用到R文件的类中,以是假如利用一般的Transform流程的话那个能够便出法子操作了.
然后经由过程文件大概类疑息举办删量编译的缓存数据,由于正在删量编译得时分我们需求对前次的R文件举办一次纪录,不然删量状况下便会呈现缺得的成绩。那部门特别简单发作正在路由表删量的过程当中。
两次扫描

假如我们把文件扫描的操作拆分红两个部门,第一次只举办数据搜集,第两次则是正在第一次搜集完数据的根底上正在来做修正,是否是就能够了呢?
R文件内乱联这类庞大的asm操作的时分,我们同理是否是就能够十分完善的打点那部门成绩了呢。
第一次扫描我们只举办asm文件会见,而没有举办asm修正。我们正在那个过程当中只搜集我们所需求的数据疑息,固然此次操作我们没有会举办任何的asm交换操作战文件写进操作,只会将文件转化成asm语法相干的。固然那里是用tree api仍是core api便随意了。
  asm 的依靠库有两种 tree api 战core api ,差别便是tree api 基于node 语法树,而core api 速率会更快。
  1. api &#39;org.ow2.asm:asm:9.2&#39;
  2. api &#39;org.ow2.asm:asm-tree:9.2&#39;
复造代码
第两次asm操作的时分我们会举办文件copy操作和类交换等等,第两次的时分我们会正在第一次搜集到的类数据的,以后将本来要做的类交换大概办法交换等复原出去。
列位能够认真品一品,是否是根本上任何庞大的皆能够基于那套逻辑来操作。可是我仍是没有是出格倡议各人来写这类,究竟结果也仍是比较简单出乌锅的。
删量缓存

那部门我觉得路由表的删量便很简单注释那个状况。
当我们要举办第两次删量编译的时分,因为删量编译的特征,只要变更文件需求举办修正,可是那个时分之前的路由表是需求举办复原。
那部门能够参考下我本人写的路由的Transform大概DRouter,我之前阐发过,由于我的路由表的注册类是class,而没有是jar。以是我是经由过程asm读与当前类举办上一次的路由表回溯的。以后我便会将本次的删编削操作感化正在那个注册类上就好了。
DRouter则是天生了一个json文件,经由过程json文件来纪录上一次的路由表,然后正在删量编译的时分对那个路由表举办修正,然后等此次编译完成以后将json文件举办笼盖操作。
而我们哔哩哔哩自研的BRouter的删量缓存完成则愈加诡同,我们是基于javac的task以后的,也一样是基于json文件缓存的。
Transform过期了

假如列位有爱好测验考试下晋级agp 700 版本的状况下,该当便会发明了Transform曾经被标识了烧毁了。之前森哥也引见过那部门,能够参考上面的援用哦。
  AGP Transform API 被烧毁意味着甚么
TransformAction 那个是700版本以后的api,可是恕我太菜,借出教会。
可是booster战bytex 两个牛逼的开源框架,实在皆是对Transform有所断绝的,包罗我们内乱部利用的字节码框架也是云云。
那么笼统的益处便是当发作了这类agp的api过期,交换调解的时分,我们就能够制止一切写了Transform的人一同调解了。
只需求底层举办好对应的适配事情,以后让上层开辟同窗晋级下底层库版本就好了。
TODO

那部门我也方案后绝一同笼统战开辟,共同spi一同,可酿成一个静态化框架。
主动化暴光

我之前的文章引见过闭于View的有用暴光监控(上)。我近来对那个也举办了一个小小的改进战测验考试,方案仍是测验考试下共同ASM对其举办调解。
View.OnAttachStateChangeListener

之前我们需求经由过程自定义许多layout,然后经由过程修正xml构造内乱的根节面,以后经由过程kt的拓展函数来找到详细的layout的方法去开辟。
由于触及到两部门代码,以是我小我私家观点相对来讲利用起去仍是比较烦琐的。以后我年夜佬辅导了下我那个api,实在View自己供给了一个addOnAttachStateChangeListener,他的感化战之前引见的onViewAttachedToWindow战onViewDetachedFromWindow是一样的。
如许我们就能够没有需求写自定义的View交换了,只需求给itemView插进一个挪用就好了。
  1. viewTreeObserver.addOnWindowFocusChangeListener(this)
  2.         view.addOnAttachStateChangeListener(this)
  3.     }
  4.     override fun onViewAttachedToWindow(v: View?) {
  5.         exposeChecker.updateStartTime()
  6.     }
  7.     override fun onViewDetachedFromWindow(v: View?) {
  8.         onExpose()
  9.         // exposeChecker.updateStartTime()
  10.     }
  11.     override fun onWindowFocusChanged(hasFocus: Boolean) {
  12.         if (hasFocus) {
  13.             exposeChecker.updateStartTime()
  14.         } else {
  15.             onExpose()
  16.         }
  17.     }
  18.     private fun onExpose() {
  19.         if (exposeChecker.isViewExpose(view)) {
  20.             mListener?.onExpose(exposeChecker.exposeTime)
  21.         }
  22.     }
  23. }
复造代码
简朴的道哦,胆码便上里那么一拾拾了,有爱好仍是能够来AutoTrack谁人工程来看下。
主动插进暴光监听

我们写完了上里的代码以后,便根本打点了xml圆里的成绩了,那末剩下去的便是我们需求正在RecyclerView.ViewHolder的初初化函数中插进我们的暴光监控的类就好了。
那部门逻辑相对来讲也比较简朴,我简朴道下就行了。
  1. class RecyclerViewHolderImp(classNode: ClassNode) {
  2.     init {
  3.         if (isRecyclerViewHolder(classNode.superName)) {
  4.             classNode.methods.firstOrNull {
  5.                 it.name == "<init>"
  6.             }?.apply {
  7.                 instructions.forEach {
  8.                     if (it.methodEnd()) {
  9.                         instructions.insertBefore(it, VarInsnNode(Opcodes.ALOAD, 1))
  10.                         instructions.insertBefore(it, TypeInsnNode(Opcodes.NEW,
  11.                                 "com/wallstreetcn/sample/viewexpose/AutoExposeImp"))
  12.                         instructions.insertBefore(it, InsnNode(Opcodes.DUP))
  13.                         instructions.insertBefore(it, VarInsnNode(Opcodes.ALOAD, 0))
  14.                         instructions.insertBefore(it, MethodInsnNode(Opcodes.INVOKESPECIAL, "com/wallstreetcn/sample/viewexpose/AutoExposeImp",
  15.                                 "<init>", "(Landroidx/recyclerview/widget/RecyclerView\$ViewHolder;)V", false))
  16.                         instructions.insertBefore(it, MethodInsnNode(Opcodes.INVOKESTATIC, "com/wallstreetcn/sample/viewexpose/ItemViewExtensionKt",
  17.                                 "addExposeListener", "(Landroid/view/View;Lcom/wallstreetcn/sample/viewexpose/OnExposeListener;)V", false))
  18.                     }
  19.                 }
  20.             }
  21.         }
  22.     }
  23. }
复造代码
  1. class AutoExposeImp(private val viewHolder: RecyclerView.ViewHolder) : OnExposeListener {
  2.     override fun onExpose(exposeTime: Float) {
  3.     }
  4. }
  5. fun View.addExposeListener(listener: OnExposeListener?) {
  6.     val exposeDelegate = ExposeViewDelegate(this, listener)
  7. }
复造代码
判定下当前的类是否是RecyclerView.ViewHolder的完成类,假如是便正在办法的最初插进一个AutoExposeImp的暴光完成类的静态代码。
那部门详细的源代码皆正在AndroidAutoTrack那个内乱部有sample,有爱好的老哥能够参考进修下呢。
总结

实在asm的易度其实不算出格的下吧,只需您多测验考试多写写多调试,其实不需求您有多智慧,就能够把握那门本事的,并且有反背东西协助的状况下哦,实在更多的操作便是相似复造黏揭罢了。
此外另有便是有时机多了解多看看一些很强的开源框架,他们的完成是甚么。能够协助我们来大白战笼统代码。
  booster 森哥的Gradle开源框架 写的实的十分的棒 森哥牛逼 宇宙第一
  ByteX 字节的字节码开源框架 也是一个十分牛逼的框架了
  lancet 我们年夜佬晚期做品 也是牛逼到离谱的一个字节码框架
  BRouter 我们哔哩哔哩的路由框架 实的牛逼
  DRouter 滴滴的路由 实在有面面意义 为了撙节编译工夫 以是局部皆是基于Transform的


免责声明:假如进犯了您的权益,请联络站少,我们会实时删除侵权内乱容,感谢协作!
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,按照目前互联网开放的原则,我们将在不通知作者的情况下,转载文章;如果原文明确注明“禁止转载”,我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话,请您发送邮箱:Cdnjson@163.com提供相关证明,我们将积极配合您!
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。
回复 关闭延时

使用道具 举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则