菜鸟科技网

Android dx命令如何使用?

什么是 dx 命令?

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

Android dx命令如何使用?-图1
(图片来源网络,侵删)

核心功能: 将 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

Android dx命令如何使用?-图2
(图片来源网络,侵删)

基本语法

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 替代 dxd8 更快、更小,并且原生支持 MultiDex,但在一些旧项目或特定构建脚本中,你可能还会看到 dx 的身影。

dx 的演进:从 dxd8

dx 虽然功能强大,但存在一些问题:

  • 速度慢: 转换过程非常耗时,尤其是在大型项目中。
  • 体积大:dx.jar 自身文件较大。
  • 老旧: 代码库维护多年,难以进行现代化改造。

为了解决这些问题,Google 开发了新的 D8 工具。

D8 的优势:

  1. 速度快: 比快 10 倍以上。
  2. 体积小:lib/d8.jardx.jar 小得多。
  3. 现代设计: 代码库更简洁,易于维护。
  4. 原生支持: 原生支持完整的 Java 8+ 语言特性。
  5. 内置 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+ (推荐): 你几乎永远不会手动调用 dxd8,Gradle 构建系统会在编译 Java/Kotlin 代码后,自动调用 d8 来生成 DEX 文件,这个过程是透明的,你只需要在 build.gradle 文件中正确配置 MultiDex 即可。

    // app/build.gradle
    android {
        compileSdk 34
        defaultConfig {
            ...
            multiDexEnabled true // 启用 MultiDex
        }
    }
  • 如果你维护旧项目或使用构建脚本: 你可能会在 build.gradleandroid 块中看到 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 流程视为新的标准。

分享:
扫描分享到社交APP
上一篇
下一篇