Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

从命令行编译您的应用

您可以使用 Gradle 封装容器命令行工具执行 Android 项目适用的所有编译任务。它可作为 Windows 的批处理文件 (gradlew.bat) 和 Linux 与 Mac 的 shell 脚本 (gradlew.sh) 使用,而且您可以从使用 Android Studio 创建的每个项目的根目录获取该工具。

要使用封装容器运行任务,请在终端窗口中(在 Android Studio 中,依次选择 View > Tool Windows > Terminal)使用下面某个命令:

  • 在 Windows 上:
    gradlew task-name
  • 在 Mac 或 Linux 上:
    ./gradlew task-name

要查看项目的所有可用编译任务的列表,请执行 tasks

    gradlew tasks
    

本页其余部分将介绍使用 Gradle 封装容器编译和运行应用的相关基础知识。要详细了解如何设置 Android 编译系统,请参阅配置编译系统

如果您更愿意使用 Android Studio 工具而不是命令行工具,请参阅编译和运行您的应用

关于版本类型

默认情况下,每个 Android 应用都有两个版本类型:一个是调试版本,用于调试您的应用;另一个是发布版本,用于向用户发布您的应用。必须先使用证书为从每个版本生成的输出签名,然后才能将您的应用部署到设备。调试版本会使用 SDK 工具提供的调试密钥自动进行签名(此版本不安全,您不能将其发布到 Google Play 商店),而发布版本必须使用您自己的私钥进行签名。

如果您要编译应用以进行发布,还请务必使用适当的签名密钥为您的应用签名。不过,如果您刚刚入门,也可以通过构建调试 APK 在模拟器或连接的设备上快速运行您的应用。

此外,您还可以在 build.gradle 文件中定义自定义版本类型,并将其配置为通过添加 debuggable true 签名为调试版本。如需了解详情,请参阅配置编译变体

编译和部署 APK

虽然编译 app bundle 是打包您的应用并将其上传到 Play 管理中心的最佳方式,但如果您希望快速测试调试版本或将您的应用作为可部署工件与其他人分享,那么编译 APK 会更合适。

编译调试 APK

要立即测试和调试应用,您可以编译调试 APK。调试 APK 会使用 SDK 工具提供的调试密钥进行签名,并允许通过 adb 调试。

要编译调试 APK,请打开命令行,然后转到项目的根目录。要启动调试编译,请调用 assembleDebug 任务:

    gradlew assembleDebug
    

这样将在 project_name/module_name/build/outputs/apk/ 中创建一个名为 module_name-debug.apk 的 APK。该文件已使用调试密钥进行签名并使用 zipalign 对齐,因此您可以立即将其安装在设备上。

或者,要编译 APK 并立即将其安装在运行的模拟器或连接的设备上,请调用 installDebug

gradlew installDebug

上述任务名称中的“Debug”部分只是编译变体名称的驼峰式大小写版本,因此可以替换为您要组装或安装的任何版本类型或编译变体。例如,如果您有产品特性“demo”,则可以使用 assembleDemoDebug 任务编译调试版本。

要查看适用于各个变体的所有编译和安装任务(包括卸载任务),请运行 tasks 任务。

另请参阅有关如何在模拟器上运行您的应用在设备上运行您的应用的部分。

编译发布版 APK

当您准备好发布和分发您的应用时,必须编译一个使用您的私钥进行签名的发布版 APK。如需了解详情,请转到有关如何从命令行为您的应用签名的部分。

将您的应用部署到模拟器

要使用 Android 模拟器,您必须使用 Android Studio 创建 Android Virtual Device (AVD)

有了 AVD 后,您便可以启动 Android 模拟器并安装您的应用,具体步骤如下:

  1. 在命令行中,转到 android_sdk/tools/,并通过指定 AVD 启动模拟器:

    emulator -avd avd_name

    如果您不确定 AVD 名称,请执行 emulator -list-avds

  2. 现在,您可以使用关于如何编译调试 APK 的部分中提及的任意一项 Gradle 安装任务或使用 adb 工具来安装您的应用。

    如果使用开发者预览版 SDK(如果 targetSdkVersion 是字母,而非数字)编译 APK,则您必须让 install 命令带有 -t 选项,才能安装测试 APK。

        adb install path/to/your_app.apk
        

    您编译的所有 APK 都保存在 project_name/module_name/build/outputs/apk/ 中。

如需了解详情,请参阅在 Android 模拟器上运行应用

将您的应用部署到物理设备

您必须先在设备上启用 USB 调试,然后才能在设备上运行您的应用。您可以在设置 > 开发者选项下找到该选项。

注意:在 Android 4.2 及更高版本中,默认情况下会隐藏开发者选项。要使其显示出来,请依次转到设置 > 关于手机,然后点按版本号七次。返回上一屏幕以查找开发者选项

您的设备设置完毕并通过 USB 连接后,您可以使用有关如何编译调试 APK 的部分中提及的 Gradle 安装任务或使用 adb 工具来安装您的应用:

    adb -d install path/to/your_app.apk
    

您编译的所有 APK 都保存在 project_name/module_name/build/outputs/apk/ 中。

如需了解详情,请参阅在硬件设备上运行应用

编译 app bundle

Android App Bundle 包含应用的所有经过编译的代码和资源,但 APK 生成及签名则延后到 Google Play 来完成。与 APK 不同的是,您无法将 app bundle 直接部署到设备。因此,如果您希望快速测试 APK 或与其他人分享 APK,应改为编译 APK

要编译 app bundle,最简单的方法是使用 Android Studio。不过,如果需要从命令行编译 app bundle,您可以使用 Gradle 或 bundletool 来执行这项操作(如下面几个部分中所述)。

使用 Gradle 编译 app bundle

如果您更愿意从命令行生成 app bundle,请在应用的基础模块上运行 bundleVariant Gradle 任务。例如,以下命令会为基础模块的调试版本编译 app bundle:

./gradlew :base:bundleDebug
    

如果您要编译已签名的 bundle 以上传到 Play 管理中心,则需要先使用应用的签名信息来配置基础模块的 build.gradle 文件。要了解详情,请转到有关如何配置 Gradle 来为您的应用签名的部分。例如,您可以随后编译应用的发布版本,Gradle 会自动生成 app bundle,并使用您在 build.gradle 文件中提供的签名信息为其签名。

如果您想改为将为 app bundle 签名作为单独的步骤来执行,则可以从命令行使用 jarsigner 为您的 app bundle 签名。

使用 bundletool 编译 app bundle

bundletool 是一个命令行工具,Android Studio、Android Gradle 插件和 Google Play 使用这项工具将应用的经过编译的代码和资源转换为 app bundle,并根据这些 bundle 生成可部署的 APK。

因此,虽然使用 bundletool 测试 app bundle 并在本地重新创建 Google Play 生成 APK 的方式很有用,但您通常不需要调用 bundletool 来编译 app bundle 本身,而应使用 Android Studio 或 Gradle 任务(如前面几个部分中所述)。

不过,如果您不想使用 Android Studio 或 Gradle 任务来编译 bundle(例如,如果您使用自定义编译工具链),那么您可以从命令行使用 bundletool 根据预编译的代码和资源来编译 app bundle。如果您还没有下载 bundletool,请从 GitHub 代码库下载 bundletool

本部分介绍了如何打包应用的经过编译的代码和资源,以及如何从命令行使用 bundletool 将其转换为 Android App Bundle。

以 proto 格式生成清单和资源

bundletool 要求关于应用项目的某些信息(如应用的清单和资源)采用 Google 的协议缓冲区格式,这种格式也称为“protobuf”,并使用 *.pb 文件扩展名。Protobuf 提供了一种无关乎语言和平台且可扩展的机制,用于对结构化数据进行序列化。它与 XML 类似,但更小、更快,也更简单。

下载 AAPT2

您可以使用 Google Maven 代码库中的最新版 AAPT2 以 protobuf 格式生成应用的清单文件和资源表。

要从 Google 的 Maven 代码库下载 AAPT2,请按以下步骤操作:

  1. 代码库索引中依次转到 com.android.tools.build > aapt2
  2. 复制最新版 AAPT2 的名称。
  3. 将复制的版本名称插入以下网址并指定目标操作系统:https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/aapt2-version/aapt2-aapt2-version-[windows | linux | osx].jar

    例如,要下载适用于 Windows 的版本 3.2.0-alpha18-4804415,您应使用:https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/3.2.0-alpha18-4804415/aapt2-3.2.0-alpha18-4804415-windows.jar

  4. 在浏览器中导航到该网址,系统应该会随即开始下载 AAPT2。

  5. 解压缩刚刚下载的 JAR 文件。

您可以通过以下命令,使用 AAPT2 编译应用的资源:

    aapt2 compile \
    project_root/module_root/src/main/res/drawable/Image1.png \
    project_root/module_root/src/main/res/drawable/Image2.png \
    -o compiled_resources/
    

在链接阶段(在此阶段,AAPT2 会将各种编译的资源链接到一个 APK 中),通过添加 --proto-format 标记,指示 AAPT2 将应用的清单和编译的资源转换为 protobuf 格式,如下所示:

    aapt2 link --proto-format -o output.apk \
    -I android_sdk/platforms/android_version/android.jar \
    --manifest project_root/module_root/src/main/AndroidManifest.xml \
    -R compiled_resources/*.flat \
    --auto-add-overlay
    

接下来,您可以从输出 APK 提取内容,如应用的 AndroidManifest.xmlresources.pb 及其他资源文件(这些文件现在采用 protobuf 格式)。在准备 bundletool 编译 app bundle 所需的输入时,您需要用到这些文件(如下文所述)。

打包预编译的代码和资源

您必须先提供 ZIP 文件(每个 ZIP 文件包含给定应用模块的经过编译的代码和资源),然后再使用 bundletool 为您的应用生成 app bundle。每个模块的 ZIP 文件的内容和组织方式都与 Android App Bundle 格式非常类似。例如,您应该为应用的基础模块创建一个 base.zip 文件,并按如下方式组织其内容:

文件或目录 说明
manifest/AndroidManifest.xml 模块的清单,采用 protobuf 格式。
dex/... 此目录包含应用的一个或多个编译的 DEX 文件。这些文件应按如下方式命名:classes.dexclasses2.dexclasses3.dex,依此类推。
res/... 包含模块的资源,这些资源采用 protobuf 格式,适用于所有设备配置。子目录和文件的组织方式应与典型的 APK 类似。
root/...assets/...lib/... 这些目录与关于 Android App Bundle 格式的部分中所属的目录完全相同。
resources.pb 应用的资源表,采用 protobuf 格式。

准备好每个应用模块的 ZIP 文件后,您可以将其传递给 bundletool 以编译 app bundle(如下文所述)。

使用 bundletool 编译 app bundle

要编译 app bundle,请使用 bundletool build-bundle 命令,如下所示:

    bundletool build-bundle --modules=base.zip --output=mybundle.aab
    

下表更详细地描述了 build-bundle 命令的标记:

标记 说明
--modules=path-to-base.zip, path-to-module2.zip,path-to-module3.zip 指定 bundletool 编译 app bundle 时应使用的模块 ZIP 文件的列表。
--output=path-to-output.aab 指定输出 *.aab 文件的路径和文件名。
--config=path-to-BundleConfig.json 指定可用于自定义编译流程的可选配置文件的路径。要了解详情,请参阅关于自定义下游 APK 生成的部分。
--metadata-file=target-bundle-path:local-file-path 指示 bundletool 将可选的元数据文件打包在 app bundle 内。您可以使用此文件添加一些数据,如 ProGuard 映射或应用的 DEX 文件的完整列表,这些数据可能对工具链或应用商店中的其他步骤很有用。

target-bundle-path 可指定一个相对于 app bundle 的根目录的路径,您可以在该路径下打包元数据文件;local-file-path 可指定本地元数据文件本身的路径。

自定义下游 APK 生成

App bundle 包含一个 BundleConfig.pb 文件,它可提供应用商店(如 Google Play)根据 bundle 生成 APK 时所需的元数据。虽然 bundletool 会为您创建此文件,但您可以在 BundleConfig.json 文件中配置元数据的某些方面,并将其传递给 bundletool build-bundle 命令。bundletool 随后会转换此文件并将其与每个 app bundle 中包含的 protobuf 版本进行合并。

例如,您可以控制要启用或停用哪些类别的配置 APK。以下 BundleConfig.json 文件示例将停用各自以不同语言为目标的配置 APK(即,所有语言的资源包含在各自的基础功能或动态功能 APK 中):

{
      "optimizations": {
        "splitsConfig": {
          "splitDimension": [{
            "value": "LANGUAGE",
            "negate": true
          }]
        }
      }
    }
    

BundleConfig.json 文件中,您还可以指定在使用 glob 模式打包 APK 时要让哪些文件类型保持未压缩状态,如下所示:

{
      "compression": {
        "uncompressedGlob": ["res/raw/**", "assets/**.uncompressed"]
      }
    }
    

请记住,默认情况下,bundletool 不会压缩应用的原生库(在 Android 6.0 或更高版本中)和资源表 (resources.arsc)。有关可以在 BundleConfig.json 中配置哪些内容的完整说明,请查看使用 Proto3 语法编写的 bundletool config.proto 文件

通过 app bundle 部署您的应用

如果您已编译 app bundle 并为其签名,请使用 bundletool 生成 APK 并将其部署到设备。

从命令行为您的应用签名

不需要 Android Studio 也可以为您的应用签名。您可以从命令行为您的应用签名(对于 APK,使用 apksigner;对于 app bundle,使用 jarsigner),或在编译期间配置 Gradle 来为您的应用签名。无论使用哪种方式,您都需要先使用 keytool 生成一个私钥,如下所示:

    keytool -genkey -v -keystore my-release-key.jks
    -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
    

上面的示例会提示您输入密钥库和密钥的密码,并提示您在“Distinguished Name”字段中为您的密钥输入相应的名称。随后,它会生成一个名为 my-release-key.jks 的密钥库文件,并将其保存在当前目录中(您可以根据自己的喜好将其移至任何位置)。该密钥库包含一个有效期为 10,000 天的密钥。

现在,您可以手动为您的 APK 或 app bundle 签名,也可以在编译过程中配置 Gradle 来为您的应用签名(如下文所述)。

从命令行手动为您的应用签名

如果要从命令行为 app bundle 签名,您可以使用 jarsigner。如果要为 APK 签名,您需要使用 zipalignapksigner(如下所述)。

  1. 打开命令行(在 Android Studio 中,依次选择 View > Tool Windows > Terminal),然后转到未签名的 APK 所在的目录。
  2. 使用 zipalign 对齐未签名的 APK:

        zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
        

    zipalign 可以确保所有未压缩的数据的开头均相对于文件开头部分执行特定的字节对齐,这样可减少应用消耗的 RAM 量。

  3. 通过 apksigner 使用您的私钥为 APK 签名:

        apksigner sign --ks my-release-key.jks --out my-app-release.apk my-app-unsigned-aligned.apk
        

    在本例中,在使用单密钥库文件 my-release-key.jks 中存储的私钥和证书为 APK 签名后,将以 my-app-release.apk 的形式输出签名的 APK。

    apksigner 工具支持其他签名选项,包括使用单独的私钥和证书文件为 APK 文件签名,以及由多个签名者为 APK 签名。如需了解详情,请参阅 apksigner 参考信息。

    注意:要使用 apksigner 工具,您必须已安装 Android SDK Build Tools 的修订版 24.0.3 或更高版本。您可以使用 SDK 管理器更新此软件包。

  4. 验证您的 APK 是否已签名:

        apksigner verify my-app-release.apk
        

配置 Gradle 来为您的应用签名

打开模块级 build.gradle 文件,并添加带有 storeFilestorePasswordkeyAliaskeyPassword 条目的 signingConfigs {} 块,然后将该对象传递到您的版本类型中的 signingConfig 属性。例如:

android {
        ...
        defaultConfig { ... }
        signingConfigs {
            release {
                // You need to specify either an absolute path or include the
                // keystore file in the same directory as the build.gradle file.
                storeFile file("my-release-key.jks")
                storePassword "password"
                keyAlias "my-alias"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                signingConfig signingConfigs.release
                ...
            }
        }
    }
    

现在,当您通过调用 Gradle 任务来编译您的应用时,Gradle 会为您的应用签名(并运行 zipalign)。

此外,因为您已使用签名密钥配置了发布版本,所以该版本类型可以执行“安装”任务。因此,您可以使用 installRelease 任务在模拟器或设备上编译、对齐、签署和安装发布版 APK。

使用您的私钥签名的应用已做好分发准备,但您应先详细了解如何发布您的应用,并查看 Google Play 发布核对清单