d8
是一种命令行工具,Android Studio 和 Android Gradle 插件使用该工具来将项目的 Java 字节码编译为在 Android 设备上运行的 DEX 字节码。d8
支持您在应用的代码中使用 Java 8 语言功能。
d8
还作为独立工具纳入了 Android 构建工具 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
|
在 |
|
强制启用 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 是“信息”“警告”和“错误”之一,而可选的 type 是诊断的简单或完全限定的 Java 类型名称。如果未指定 type,则会映射 from-level 上的所有诊断。 请注意,无法映射严重编译器错误。 |
--version
|
输出您当前使用的 d8 版本。
|
--help
|
输出与使用 d8 相关的帮助文本。
|
执行增量构建
为了在开发过程中提高构建速度(例如提高持续集成 build 的速度),请指示 d8
仅编译项目的部分 Java 字节码。例如,如果您启用了按类 dexing 处理,则只需重新编译自上次构建以来修改过的类。
以下命令可执行几个类的增量构建,并启用按类 dexing 处理。该命令还可为增量构建指定输出目录。
d8 MainActivity.class R.class --intermediate --file-per-class --output ~/build/intermediate/dex
d8
在执行增量构建时,会将一些额外的信息存储在 DEX 输出中。随后在完整构建应用时,d8
会利用这些信息来正确处理 --main-dex-list
选项以及合并 DEX 文件。
例如,d8
在处理 Java 8 lambda 类时,会记录为每个输入类创建的 lamdba 类。在执行完整构建的过程中,当 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 字节码的路径,即使您不打算将所有 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