说说 bytex 的 extension (1) accessinline

说说 bytex 的 extension (1) access-inline

本文谈论一个比较小的内容,说一下 byteX 自带的一个插件 —— ”access-inline“ 的实现

access-inline 是用来解决什么问题的?

众所周知,Android 应用的方法数量是有过一些问题的,因为一个 dex 里的方法数量不能超过 65535 ,所以当项目达到一定程度后,就不能够使用一个 dex 文件来承载所有的字节码了,这时候我们就需要引入 multidex 的处理了,将一个 dex 拆分为多个 dex 甚至是许多个 dex 。

这个问题解决了,也就可以不需要担心方法数量过多导致无法打包了。

但是方法数量太多了,也会导致一些不是问题的小问题,例如

  • 包的大小增加
  • 混淆 mapping 文件里的项目增加
  • 运行时的执行的字节码指令增加

这些问题,其实对于一般的产品开发而言,都是无伤大雅的问题,不处理也是没有问题的。而本文谈论的这个 byteX 的插件,就是用来优化这个”方法数量过多“的问题滴。

和 Android 布局文件里使用 减少嵌套层级,以及 kotlin 里使用 inline 修士方法减少方法调用层级类似,access-inline 这个方法也是将一部分方法调用改为直接调用,借此来实现”减少方法数量“的目的。

java 语言里有一种类叫做 ”内部类“,内部类可以直接访问其外部类的属性和方法。实际在字节码的实现里,内部类也是一个独立的类,只不过持有了外部类的引用而已。

而其之所以可以访问外部类的属性和方法,是因为 java 在编译的时候,专门为这个内部类生成了若干个静态方法,将内部类对外部类的访问,都转成了对这个静态方法的调用了。而本文要说的 access-inline 插件,就是要将这部分方法改为代码内联,也就是改为直接调用,而不是通过调用生成的静态方法获取属性或者是执行方法。

access-inline 是怎么处理以将这部分方法内联化的呢?

我们这样想:java 编译器处理内部类的时候,做了如下两件事情:

  1. 为内部类访问外部类的属性/方法 生成静态方法用做代理。
  2. 将内部类对外部类的属性/方法 的获取调用改为对上面提到的方法的调用。

而 access-inline 插件的目标是 : 内部类访问外部类的 属性/方法 的时候直接进行 获取/调用。

那么对于上述两点分别解决即可,改动点就是:

  1. 修改后,内部类对外部类的 属性/方法 的获取/调用 就是直接访问的了,所以原来额外生成的方法已经不需要了,将其删除掉。
  2. 将字节码生成的通过静态方法访问的方式,改为直接进行访问。

这里面涉及到一些细节:

  1. 删除方法,那么哪些方法需要删除?
  2. 将访问静态方法修改为直接进行访问
    1. 哪些静态方法需要修改?这个问题和问题 1. 是一样的,等下做简略的回答。
    2. 怎么修改字节码?

上述的问题都是可以解决的,本文尽量避过源码级别的解释,使用白话文讲解核心的原理,因为需要了解源码的人,是可以去 github 上找源码进行查看的,本文就不解释源码了。

问题 1, 哪些方法需要删除 ? 因为这类方法是 java 编译器生成的,所以我们需要尽量确保判断条件只命中这类生成的方法,而不会将项目里正常的方法”误杀“。这涉及了 java 编译器的处理逻辑,在此我直接给出 access-inline 官方的判断条件:

  1. 是生成的方法 (字节码中的方法,有一个标记位 isSynthetic 是用来表示是否是生成的方法的。)
  2. 是静态方法。
  3. 方法名称以 “access$” 开头。这点是 java 编译器的规定。

问题 2,怎么修改字节码?这个需要字节码处理功能,在 byteX 中,是使用 asm 来进行处理的,借助 asm 的框架可以实现字节码的增加、删除、修改等操作。

后记

byteX 中自带的插件,都是比较有趣的功能。推荐有时间精力并且感兴趣的朋友可以去 github 上查看,这种有趣的插件,只是学习其功能,也可以学习到很多知识,扩大眼界。例如 asm 处理字节码等。

byteX 官方地址 :

[https://github.com/bytedance/ByteX](

原文地址:https://www.cnblogs.com/wkmcyz/p/15721673.html