d8
是 Android Studio 和 Android Gradle 插件用来将项目 Java 字节码编译成可在 Android 设备上运行的 DEX 字节码的命令行工具。d8
允许您在应用代码中使用 Java 8 语言特性。
d8
也包含在 Android Build Tools 28.0.1 及更高版本中:android_sdk/build-tools/version/
。
一般用法
d8
只需要要转换成 DEX 字节码的已编译 Java 字节码的路径。例如
d8 MyProject/app/build/intermediates/classes/debug/*/*.class
输入字节码可以是任何组合的 *.class
文件或容器,例如 JAR、APK 或 ZIP 文件。您还可以包含 DEX 文件,以便 d8
合并到 DEX 输出中,这在包含增量构建的输出时非常有用。
默认情况下,d8
将 Java 字节码编译成优化的 DEX 文件,并包含可在运行时用于调试代码的调试信息。但是,您可以包含可选标志以执行增量构建,指定应编译到主 DEX 文件中的类,以及指定使用 Java 8 语言特性所需的其他资源的路径。
d8 path-to-input-files [options]
下表描述了您可以与 d8
一起使用的可选标志
选项 | 说明 |
---|---|
--debug
|
编译 DEX 字节码以包含调试信息,例如调试符号表。 此选项默认启用。要在 DEX 字节码中包含调试信息, 编译应用或库的发行版本 DEX 文件时,请改用 |
--release
|
编译 DEX 字节码时不包含调试信息。但是, 编译供公开发布的字节码时,请传递此标志。 |
--output path
|
指定所需的 DEX 输出路径。默认情况下, 如果指定 ZIP 或 JAR 文件的路径和名称, |
--lib android_sdk/platforms/api-level/android.jar
|
指定 Android SDK 的 android.jar 的路径。当编译使用 Java 8 语言特性的字节码时,需要此标志。 |
--classpath path
|
指定 d8 可能需要编译项目的 DEX 文件的类路径资源。特别是,当编译使用 Java 8 语言特性的字节码时,d8 需要您指定某些资源。 |
--min-api number
|
指定您希望输出 DEX 文件支持的最低 API 级别。 |
--intermediate
|
传递此标志可让 d8 知道您没有编译项目 Java 字节码的完整集合。此标志在执行增量构建时非常有用。 d8 不会编译您期望在设备上运行的优化 DEX 文件,而是创建中间 DEX 文件并将其存储在指定的输出路径或默认路径中。当您要编译打算在设备上运行的 DEX 文件时,请排除此标志并将中间 DEX 类路径指定为输入。 |
--file-per-class
|
将每个类编译成单独的 DEX 文件。 启用此标志允许您通过仅重新编译已更改的类来执行更多增量构建。在使用 Android Gradle 插件执行增量构建时,默认情况下启用此优化。 不能同时使用此标志和 |
--no-desugaring
|
禁用 Java 8 语言功能。仅当您不打算编译使用 Java 8 语言功能的 Java 字节码时,才使用此标志。 |
--main-dex-list path
|
指定一个文本文件,其中列出了 由于 Android 系统在启动您的应用时会首先加载主 DEX 文件,因此您可以使用此标志通过将某些类编译到主 DEX 文件中来优先处理启动时的某些类。这在支持旧版 multidex 时尤其有用,因为在加载旧版 multidex 库之前,只有主 DEX 文件中的类在运行时可用。 请记住,每个 DEX 文件仍然必须满足 64K 引用限制。因此,不要为主要 DEX 文件指定过多类,否则会发生编译错误。默认情况下,当使用 不能同时使用此标志和 |
--pg-map file
|
使用 file 作为分发映射文件。 |
--file-per-class-file
|
为每个输入 .class 文件生成一个单独的 DEX 文件。 将合成类与其原始类保留在一起。 |
--desugared-lib file
|
指定反糖化库配置。 file 是 JSON 格式的反糖化库配置文件。 |
--main-dex-rules file
|
用于放置在主 DEX 文件中的类的 Proguard 保留规则。 |
--main-dex-list-output file
|
将生成的主 DEX 列表输出到 |
|
强制启用 javac 生成的断言代码。 |
|
强制禁用 javac 生成的断言代码。这是生成 DEX 文件时 javac 断言代码的默认处理方式。 |
|
不要更改 javac 生成的断言代码。这是生成 class 文件时 javac 断言代码的默认处理方式。 |
|
将 javac 和 kotlinc 生成的断言代码更改为使用每个断言错误调用方法 handler method ,而不是抛出它。handler method 指定为类名后跟一个点和方法名。处理程序方法必须接受类型为 java.lang.Throwable 的单个参数,并且返回类型为 void 。 |
--thread-count number of threads
|
指定用于编译的线程数。如果未指定,则此数字基于启发式算法,并考虑核心数。 |
--map-diagnostics[ :type] from-level to-level
|
将报告为 from-level 的 type(默认为任何)诊断映射到 to-level,其中 from-level 和 to-level 为 'info'、'warning' 或 'error' 之一,可选的 type 是诊断的简单或完全限定的 Java 类型名称。如果未指定 type,则映射所有位于 from-level 的诊断。请注意,无法映射致命编译器错误。 |
--version
|
打印您当前使用的 d8 版本。 |
--help
|
打印使用 d8 的帮助文本。 |
执行增量构建
为了提高开发过程中的构建速度(例如,对于持续集成构建),请指示 d8
仅编译项目 Java 字节码的子集。例如,如果您启用了每个类的 DEX 处理,则可以仅重新编译自上次构建以来已修改的类。
以下命令执行少量类的增量构建并启用每个类的 DEX 处理。该命令还为增量构建指定了输出目录。
d8 MainActivity.class R.class --intermediate --file-per-class --output ~/build/intermediate/dex
当 d8
执行增量构建时,它会将附加信息存储在 DEX 输出中。d8
稍后将使用该信息在应用的完整构建过程中正确处理 --main-dex-list
选项并合并 DEX 文件。
例如,在处理 Java 8 lambda 类时,d8
会跟踪为每个输入类创建了哪些 lambda 类。在完整构建期间,当 d8
将类包含在主 DEX 文件中时,它会查阅元数据以确保为该类创建的所有 lambda 类也包含在主 DEX 文件中。
如果您已经通过多个增量构建将项目的所有字节码编译到 DEX 文件中,请通过将中间 DEX 文件的目录传递给 d8
来执行完整构建,如下面的命令所示。此外,您可以使用 --main-dex-list
指定您希望 d8
编译到主 DEX 文件中的类。因为输入是一组已编译成 DEX 字节码的文件,所以此构建应该比干净构建完成得更快。
d8 ~/build/intermediate/dex --release --main-dex-list ~/build/classes.txt --output ~/build/release/dex
编译使用 Java 8 语言功能的字节码
d8
使您可以 在代码中使用 Java 8 语言功能,这通过称为 *反糖化* 的编译过程实现。反糖化将这些有用的语言功能转换为可以在 Android 平台上运行的字节码。
Android Studio 和 Android Gradle 插件包含 d8
为您启用反糖化所需的类路径资源。但是,当从命令行使用 d8
时,您需要自己包含它们。
其中一个资源是来自您的目标 Android SDK 的 android.jar
。此资源包含一组 Android 平台 API。使用 --lib
标志指定其路径。
另一个资源是编译到您的项目中的 Java 字节码集,您目前没有将其编译到 DEX 字节码中,但需要将其编译到 DEX 字节码中才能编译其他类。
例如,如果您的代码使用 默认和静态接口方法(这是 Java 8 语言功能),则需要使用此标志来指定项目所有 Java 字节码的路径,即使您不打算将所有字节码编译到 DEX 字节码中也是如此。这是因为 d8
需要此信息来了解项目的代码并解析对接口方法的调用。
以下代码示例执行访问默认接口方法的类的增量构建。
d8 MainActivity.class --intermediate --file-per-class --output ~/build/intermediate/dex --lib android_sdk/platforms/api-level/android.jar --classpath ~/build/javac/debug