Android D8 编译器 和 R8 工具(1)

本文介绍了Android开发中的D8编译器和R8工具,它们分别作为dex字节码文件编译器和代码压缩混淆工具。D8编译器在Android Studio 3.4版本成为默认编译器,具有更快的编译速度和更小的文件大小。R8工具在3.4版本中替代ProGuard,用于代码压缩和混淆。文章还探讨了D8和R8的发展历程,以及如何在构建配置中启用或禁用它们。此外,文章提到了Android对Java 8特性的脱糖过程,特别是Lambda表达式的使用和转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

dex 过程

  • javac:用于将 .java 文件编译为 .class 文件;
  • desugar:用于将 Java 8 中的特性在 Android 平台上适配;
  • ProGuard:用于提出无用的 Java 代码并且做一些优化;
  • DX):将所有的 Java 代码转换为 DEX 格式。

Android Studio 3.X 以后,Google 分别引入 D8 编译器和 R8 工具作为新的 DEX 编译器和混淆压缩工具。

1. D8、R8 发展历程

Android Studio 版本Android Gradle Plugin 版本变更
3.13.0.1引入 D8
3.23.2.0引入 R8、D8 脱糖默认开启
3.43.4.0默认开启 R8
1.1 D8 编译器

GoogleAndroid Studio 3.1 版本中引入 D8 编译器作为默认的 DEX 字节码文件编译器。通过在 gradle.properties 中新增 android.enableD8=true 开启 D8 编译器。

D8 编译器特点是:

  • 编译更快、时间更短;
  • DEX 编译时占用内容更小;
  • .dex 文件大小更小;
  • D8 编译的 .dex 文件拥有相同或者是更好的运行时性能;

根据 Google Android 团队使用 DexD8 编译器的测试对比数据:

d8 time.png

d8 size.png

1.2 R8 工具

GoogleAndroid Studio 3.2 中引入 R8 作为 ProGuard 的替代工具,用于代码的压缩(shrinking)和混淆(obfuscation)。通过在 gradle.properties 中新增 android.enableR8 = true 开启 R8 工具。

Disables R8 for Android Library modules only.

android.enableR8.libraries = false

Disables R8 for all modules.

android.enableR8 = false

1.3 Android Studio 3.4 版本 D8 R8 变更

Android Studio 3.4 版本中,R8desugaringshrinkingobfuscatingoptimizingdexing 都合并到一步进行执行。在 Android Studio 3.4 以前的版本编译流程如下:

compile_with_d8_proguard.png

合并之后编译流程如下:

compile_with_r8.png

注意,如果我们在 build.gradle 中配置了 useProguard = false 则不管是否开启 R8 编译都会使用 R8 进行压缩代码。

2. 脱糖

Android Studio 为使用部分 Java 8 语言功能及利用这些功能的第三方库提供内置支持。默认工具链对 javac 编译器的输出执行字节码转换(称为 desugar),从而实现新语言功能。

脱糖即在编译阶段将在语法层面一些底层字节码不支持的特性转换为基础的字节码结构,(比如 List 上的泛型脱糖后在字节码层面实际为 Object); Android 工具链对 Java8 语法特性脱糖的过程可谓丰富多彩,当然他们的最终目的是一致的:使新的语法可以在所有的设备上运行。

经过上面 D8R8 的了解,D8 已经支持脱糖,让 Java 8 提供的特性(如 lambdas)可以转换成 Java 7 特性。把脱糖步骤集成进 D8 影响了所有读或写 .class 字节码的开发工具,因为它会使用 Java 8 格式。可以在 gradle.properties 中禁用脱糖。

android.enableIncrementalDesugaring=false.
android.enableDesugar=false

2.1 Lambda 表达式

Java 8 中一个重大变更是引入 Lambda 表达式。

public class Lambda {
public static void main(String[] args) {
logDebug(msg-> System.out.println(msg), “HelloWorld”);
}

static void logDebug(Logger logger, String msg) {
logger.log(msg);
}

@FunctionalInterface
interface Logger {
void log(String msg);
}
}

通过 javac 指令将上面的 Lambda.java 转换为字节码。

$javac Lambda.java

接下来通过 javap -v 指令查看字节码的详细内容:

dengshiweideMacBook-Pro:Desktop dengshiwei$ javap -v Lambda.class
Classfile /Users/dengshiwei/Desktop/Lambda.class
Last modified 2019-5-12; size 1120 bytes
MD5 checksum 67301305720e60d4ef1ff286769768e6
Compiled from “Lambda.java”
public class Lambda
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#25 // java/lang/Object.“”😦)V
#2 = InvokeDynamic #0:#30 // #0:log:()LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 9: Logger; #̲3 = String …Logger;Ljava/lang/String;)V
#5 = InterfaceMethodref #10.#33 // LambdaKaTeX parse error: Expected 'EOF', got '#' at position 34: …lang/String;)V #̲6 = Fieldref …Logger
#11 = Utf8 Logger
#12 = Utf8 InnerClasses
#13 = Utf8
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 main
#18 = Utf8 ([Ljava/lang/String;)V
#19 = Utf8 logDebug
#20 = Utf8 (LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 29: …lang/String;)V #̲21 = Utf8 …mainKaTeX parse error: Expected 'EOF', got '#' at position 3: 0 #̲22 = Utf8 …Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#28 = MethodType #22 // (Ljava/lang/String;)V
#29 = MethodHandle #6:#42 // invokestatic Lambda.lambda$mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲30 = NameAndTyp…Logger;
#31 = Utf8 HelloWorld
#32 = NameAndType #19:#20 // logDebug:(LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 29: …lang/String;)V #̲33 = NameAndTyp…Logger
#41 = Methodref #50.#51 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲42 = Methodref …mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲43 = Utf8 …Logger;
#45 = Utf8 java/lang/System
#46 = Utf8 out
#47 = Utf8 Ljava/io/PrintStream;
#48 = Utf8 java/io/PrintStream
#49 = Utf8 println
#50 = Class #53 // java/lang/invoke/LambdaMetafactory
#51 = NameAndType #54:#57 // metafactory:(Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲52 = NameAndTyp…mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲53 = Utf8 …Lookup
#56 = Utf8 Lookup
#57 = Utf8 (Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲58 = Class …Lookup
#60 = Utf8 java/lang/invoke/MethodHandles
{
public Lambda();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.“”😦)V
4: return
LineNumberTable:
line 1: 0

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: invokedynamic #2, 0 // InvokeDynamic #0:log:()LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 26: … ldc #̲3 …Logger;Ljava/lang/String;)V
10: return
LineNumberTable:
line 3: 0
line 4: 10

static void logDebug(Lambda$Logger, java.lang.String);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

id复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-vqBhPYTc-1713713158252)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值