如果日常做Android开发的你不关注Google针对编译优化的话做的努力的话,会对D8和R8这两个名词会比较陌生。最近要升级工程的Gradle版本,正好涉及到开启D8和R8的问题,笔者就简单整理解释下这两者的作用和概念。
一张图概括Android编译器进化
图引自:https://proandroiddev.com/android-cpu-compilers-d8-r8-a3aa2bfbc109
从Java开始,JVM通过在硬件上面添加一层抽象来适配不同的CPU架构来实现跨平台,通过javac编译器将Java代码编译成字节码,进而运行在虚拟机当中,这样就无需关注底层操作系统、内存和CPU的差异,应用开发者只需要关注业务逻辑。
回到Android,我们的代码是需要跑在容量更小,电量更小的移动设备当中,JVM那套就不太适用了,所以Google就针对Android开发了Dex编译器来编译dex格式的字节码,而运行Dex字节码的Android虚拟机被称为Dalvik。因为Dalvik存在不少局限性,Google后来又退出ART虚拟机,ART使用了AOT(Ahead of Time)编译器,跟Davik的区别是,它不是在运行时解析和JIT编译,而是直接运行提前编译好的.oat文件,所以它的运行速度会更快。 按道理说到了AOT,Android的编译速度已经有了不错的效果,但是Java Android != Java SE
,Java7开始引入的新语言特性不能直接用在Android开发中,为了能够用上Java8新特性,Google增加了一步编译过程—脱糖(desugaring)
,但这一步会导致更长的编译时间,这也是为什么Google会推出D8
和R8
编译器来优化编译速度。
什么是脱糖?
脱糖 即在编译阶段将在语法层面一些底层字节码不支持的特性转换为基础的字节码结构,(比如 List 上的泛型脱糖后在字节码层面实际为 Object); Android 工具链对 Java8 语法特性脱糖的过程可谓丰富多彩,当然他们的最终目的是一致的:使新的语法可以在所有的设备上运行。
D8
D8的功能是将Java字节码转化成dex代码,D8作为DX的一个替代方案。编译流程如下图所示:
Android Studio 3.1版本开始,将D8作为默认的Dex编译器。如果想关闭D8,可以在gradle.properties
里添加如下配置:
android.enableD8=false
android.enableD8.desugaring=false
开启D8的好处
- 编译更快、时间更短
- DEX编译时占用内容更小
- .dex文件更小
- D8编译的.dex文件拥有相同或者更好的运行性能
如果你的工程已经使用Java 8尽可能开启D8编译,不然可能会出现编译错误。
R8
R8是用来替代Proguard的一个工具,是新一代的代码压缩工具。 R8之前采用D8+Proguard的形式构建,R8则将混淆和D8工具进行整合,目的是加速构建时间和减少输出apk的大小。
Gradle插件版本达到3.4.0及以上,默认会开始R8进行代码优化。如果你不想开启R8,可以在gradle.properties
里添加如下配置:
android.enableR8=false
开启R8的好处
- 代码缩减:规避64引用限制
- 资源缩减:移除不使用的资源
- 混淆代码:减小DEX文件大小
- 优化代码:进一步减小DEX文件大小
参考:https://developer.android.google.cn/studio/build/shrink-code
R8 VS Proguard
Time
Size
评测结果图引自:https://github.com/madsager/santa-tracker-android
参考资料
- https://juejin.cn/post/6844903773144350734
- https://juejin.cn/post/6914497144346902542#heading-1
- https://juejin.cn/post/6844903951846899719#heading-10
- https://blog.csdn.net/jamin0107/article/details/81123154