什么是 dx 命令?
dx 是 Android SDK 工具链中的一个核心命令行工具,它的全称是 "Dexer"。

核心功能: 将 Java 字节码(.class 文件)转换为 Android 设备和 Dalvik 虚拟机(以及后来的 ART 运行时)可以执行的 Dalvik Executable (DEX) 格式。
你可以把它想象成一个“翻译官”,它把 Java 编译器生成的通用语言(Java 字节码)翻译成 Android 系统能够理解并高效执行的专门语言(DEX 代码)。
为什么需要 dx?
- Java vs. Android: Java 源代码(
.java文件)首先被javac编译成 Java 字节码(.class文件),这些.class文件是为标准的 Java 虚拟机设计的。 - Dalvik/ART 虚拟机: Android 系统使用的是自己设计的虚拟机,最初是 Dalvik,现在是 ART,这些虚拟机不直接执行 Java 字节码,而是需要一种更优化的格式——DEX。
- 优化与合并: DEX 格式比 JAR 文件中的多个
.class文件更节省内存和存储空间。dx的一个重要作用就是将一个 App 中所有的.class文件(以及第三方库的.class文件)合并成一个或多个classes.dex文件,这对于 Android 的类加载机制至关重要。
dx 命令的基本语法和常用选项
dx 工具位于你的 Android SDK 的 build-tools 目录下,
<your_sdk_path>/build-tools/<version>/dx.jar
你不直接调用 java -jar dx.jar,而是使用一个封装好的 shell 脚本(在 Linux/macOS 上)或批处理文件(在 Windows 上),这个脚本就叫 dx。

基本语法
dx --dex [--options] <input-files> --output=<output-file>
常用选项
| 选项 | 全称 | 描述 |
|---|---|---|
--dex |
执行 DEX 转换的核心选项。 | |
--output=<file> |
--output=<file> |
指定输出的 DEX 文件路径。这是最常用的选项。--output=classes.dex。 |
--no-locals |
不将局部变量信息写入 DEX 文件,可以略微减小输出文件大小,但调试会变得困难。 | |
--no-optimize |
跳过对输入文件的字节码优化,通常不需要手动禁用,优化过程对性能有益。 | |
--verbose |
显示详细的处理过程信息,便于调试。 | |
--debug |
生成包含调试信息的 DEX 文件。 | |
--force-jumbo |
允许生成超过 64K 引用方法的 DEX 文件。(注意:这并不能真正解决 64K 方法数限制) | |
--multi-dex |
非常重要! 允许生成多个 classes.dex 文件(如 classes.dex, classes2.dex),以绕过单个 DEX 文件 64K 的方法数引用限制,这是现代 Android 开发的标配。 |
|
--minimal-main-dex |
与 --multi-dex 配合使用,确保主 DEX 文件(classes.dex)只包含启动应用所必需的类。 |
|
--set-max-idx=<number> |
设置 DEX 文件中方法或字段的索引数量上限。 |
实际使用示例
示例 1:简单的 .class 文件转 DEX
假设你有一个编译好的 MyApp.class 文件,想把它转换成 DEX。
# 假设 dx 工具在 PATH 中,或者你指定了完整路径 # 输入是 MyApp.class,输出是 classes.dex dx --dex --output=classes.dex MyApp.class
执行后,你会得到一个 classes.dex 文件。
示例 2:转换整个 build/intermediates/javac/debug/classes 目录
这是在 Android Studio 或 Gradle 构建过程中最常见的场景,Gradle 会自动调用 dx(或其现代替代品 d8)来处理编译后的所有 .class 文件。
# 假设你的 .class 文件都在这个目录下 dx --dex --output=classes.jar build/intermediates/javac/debug/classes # 输出 classes.jar 是因为 DEX 文件通常会被打包进一个 JAR 文件中, # 以方便作为库分发或直接安装。
示例 3:处理超过 64K 方法数限制(MultiDex)
当你的 App 或其依赖库的引用方法总数超过 65,536 (64K) 时,单个 classes.dex 无法容纳,这时就需要 MultiDex。
# 输入是一个包含所有 .class 文件的巨大目录 # 输出是一个 JAR 文件,但内部会包含 classes.dex, classes2.dex 等多个 DEX 文件 dx --dex --multi-dex --output=app-debug.jar build/intermediates/javac/debug/classes
注意: 从 Android Gradle Plugin 3.1.0 开始,Google 推荐使用
d8替代dx。d8更快、更小,并且原生支持 MultiDex,但在一些旧项目或特定构建脚本中,你可能还会看到dx的身影。
dx 的演进:从 dx 到 d8
dx 虽然功能强大,但存在一些问题:
- 速度慢: 转换过程非常耗时,尤其是在大型项目中。
- 体积大:
dx.jar自身文件较大。 - 老旧: 代码库维护多年,难以进行现代化改造。
为了解决这些问题,Google 开发了新的 D8 工具。
D8 的优势:
- 速度快: 比快 10 倍以上。
- 体积小:
lib/d8.jar比dx.jar小得多。 - 现代设计: 代码库更简洁,易于维护。
- 原生支持: 原生支持完整的 Java 8+ 语言特性。
- 内置 MultiDex: 无需特殊选项即可处理 MultiDex。
d8 的基本用法
d8 的用法与 dx 非常相似。
# d8 的基本语法 d8 <input-files> --output=<output-directory> # 示例:转换目录中的 .class 文件 d8 build/intermediates/javac/debug/classes --output=./dex_output # 执行后,dex_output 目录下会生成 classes.dex # 如果方法数超限,还会生成 classes2.dex, classes3.dex ...
在现代 Android 开发中的角色
在今天的 Android Studio 和 Android Gradle Plugin (AGP) 环境中:
-
如果你使用 AGP 3.1.0+ (推荐): 你几乎永远不会手动调用
dx或d8,Gradle 构建系统会在编译 Java/Kotlin 代码后,自动调用d8来生成 DEX 文件,这个过程是透明的,你只需要在build.gradle文件中正确配置 MultiDex 即可。// app/build.gradle android { compileSdk 34 defaultConfig { ... multiDexEnabled true // 启用 MultiDex } } -
如果你维护旧项目或使用构建脚本: 你可能会在
build.gradle的android块中看到dexOptions的配置,这些就是用来配置dx行为的,在新项目中,这些配置已被废弃。// 旧式配置,已不推荐 android { dexOptions { javaMaxHeapSize "4g" // 增加堆内存,防止 dx 因内存不足失败 preDexLibraries true // 预编译库,加快构建速度 jumboMode true // 启用巨模式(不推荐,应使用 MultiDex 解决方案) } }
| 特性 | dx |
d8 |
|---|---|---|
| 角色 | 传统的 DEX 转换工具 | 现代、高效的 DEX 转换工具 |
| 速度 | 慢 | 非常快 (快10倍+) |
| 体积 | dx.jar 文件大 |
d8.jar 文件小 |
| MultiDex | 需要特定选项 --multi-dex |
原生支持 |
| 现代 Java | 支持有限 | 原生支持 Java 8+ |
| 当前状态 | 已废弃 | 当前标准 |
| 使用场景 | 维护旧项目、理解底层原理 | 所有新项目、现代构建系统 |
dx 是 Android 发展史上一个里程碑式的工具,理解它的工作原理对于掌握 Android 构建过程非常有帮助,但在日常开发中,你应该将 d8 以及它背后自动化的 Gradle 流程视为新的标准。
