bundletool

bundletool 是 Android Studio、Android Gradle 插件和 Google Play 用于构建 Android 应用包的基础工具。bundletool 可以将应用包转换为部署到设备的各种 APK。

Android SDK 包 (ASB) 及其 APK 均使用 bundletool 构建。它也作为命令行工具提供,因此您可以自行构建应用包和 SDK 包,并重新创建 Google Play 服务器端对您的应用 APK 或您 已启用运行时的 SDK 的 APK 的构建。

下载 bundletool

如果您尚未下载,请从 GitHub 代码库 下载 bundletool

构建和测试应用包

您可以使用 Android Studio 或 bundletool 命令行工具构建 Android 应用包,然后测试从此应用包生成 APK。

构建应用包

使用 Android Studio 和 Android Gradle 插件 构建和签署 Android 应用包。但是,如果无法使用 IDE(例如,因为您使用的是持续构建服务器),您也可以 从命令行构建应用包 并使用 jarsigner 对其进行签署。

有关使用 bundletool 构建应用包的更多信息,请参阅 使用 bundletool 构建应用包

从应用包生成一组 APK

构建 Android 应用包后,测试 Google Play 如何使用它生成 APK 以及这些 APK 部署到设备后的行为。

您可以通过两种方式测试应用包

本部分介绍如何使用 bundletool 在本地测试应用包。

bundletool 从您的应用包生成 APK 时,它会将生成的 APK 包含在一个名为APK 集成归档文件的容器中,该容器使用 .apks 文件扩展名。要为应用支持的所有设备配置从应用包生成 APK 集,请使用 bundletool build-apks 命令,如下所示

bundletool build-apks --bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks

如果要将 APK 部署到设备,还需要包含应用的签署信息,如下面的命令所示。如果您未指定签署信息,bundletool 会尝试使用调试密钥为您签署 APK。

bundletool build-apks --bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks
--ks=/MyApp/keystore.jks
--ks-pass=file:/MyApp/keystore.pwd
--ks-key-alias=MyKeyAlias
--key-pass=file:/MyApp/key.pwd

下表详细描述了在使用bundletool build-apks命令时可以设置的各种标志和选项。

表 1. bundletool build-apks命令的选项

标志 描述
--bundle=path (必需) 指定使用 Android Studio 构建的应用 bundle 的路径。要了解更多信息,请阅读构建您的项目
--output=path (必需) 指定输出.apks文件的名称,该文件包含应用的所有 APK 工件。要测试此文件中的工件,请按照有关如何将 APK 部署到连接的设备部分中的步骤操作。
--overwrite 使用--output选项指定的路径覆盖任何现有的输出文件。如果您不包含此标志并且输出文件已存在,则会收到构建错误。
--aapt2=path 指定 AAPT2 的自定义路径。默认情况下,bundletool包含其自己的 AAPT2 版本。
--ks=path (可选) 指定用于签署 APK 的部署密钥库的路径。如果您不包含此标志,bundletool将尝试使用调试签名密钥签署您的 APK。
--ks-pass=pass:password

--ks-pass=file:/path/to/file
指定您的密钥库密码。如果您以纯文本形式指定密码,请使用pass:限定它。如果您传递包含密码的文件的路径,请使用file:限定它。如果您使用--ks标志指定密钥库,而没有指定--ks-pass,则bundletool会提示您从命令行输入密码。
--ks-key-alias=alias 指定要使用的签名密钥的别名。
--key-pass=pass:password

--key-pass=file:/path/to/file
指定签名密钥的密码。如果您以纯文本形式指定密码,请使用pass:限定它。如果您传递包含密码的文件的路径,请使用file:限定它。

如果此密码与密钥库本身的密码相同,则可以省略此标志。

--connected-device 指示bundletool构建针对连接设备配置的 APK。如果您不包含此标志,bundletool将为您的应用支持的所有设备配置生成 APK。
--device-id=serial-number 如果您连接了多个设备,请使用此标志指定要将应用部署到的设备的序列 ID。
--device-spec=spec_json 提供.json文件的路径,该文件指定要定位的设备配置。要了解更多信息,请转到有关如何生成和使用设备规范 JSON 文件的部分。
--mode=universal 将模式设置为universal。如果您希望bundletool构建一个包含应用所有代码和资源的单个 APK,以便 APK 与应用支持的所有设备配置兼容,则可以使用此选项。

注意:bundletool仅在通用 APK 中包含在其清单中指定<dist:fusing dist:include="true"/>的功能模块。要了解更多信息,请阅读有关功能模块清单的内容。

请记住,这些 APK 比针对特定设备配置优化的 APK 大。但是,它们更容易与内部测试人员共享,例如,内部测试人员希望在多个设备配置上测试您的应用。

--local-testing 启用应用 bundle 进行本地测试。本地测试允许快速迭代测试周期,而无需上传到 Google Play 服务器。

有关如何使用--local-testing标志测试模块安装的示例,请参阅本地测试模块安装

将 APK 部署到连接的设备

生成一组 APK 后,bundletool可以将该集中正确的 APK 组合部署到连接的设备。

例如,如果您有一个运行 Android 5.0(API 级别 21)或更高版本的连接设备,则bundletool会推送在该设备上运行您的应用所需的基 APK、功能模块 APK 和配置 APK。或者,如果您的连接设备运行的是 Android 4.4(API 级别 20)或更低版本,则bundletool会搜索一个兼容的多 APK 以部署到您的设备。

要从 APK 集部署您的应用,请使用install-apks命令并使用--apks=/path/to/apks标志指定 APK 集的路径,如以下命令所示。如果您连接了多个设备,请通过添加--device-id=serial-id标志来指定目标设备。

bundletool install-apks --apks=/MyApp/my_app.apks

生成特定于设备的 APK 集

如果您不想为应用支持的所有设备配置构建 APK 集,则可以使用--connected-device选项构建仅针对连接设备配置的 APK,如以下命令所示。如果您连接了多个设备,请通过包含--device-id=serial-id标志来指定目标设备。

bundletool build-apks --connected-device
--bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks

生成和使用设备规范 JSON 文件

bundletool可以生成一个针对 JSON 文件指定的设备配置的 APK 集。要首先为连接的设备生成 JSON 文件,请运行以下命令

bundletool get-device-spec --output=/tmp/device-spec.json

bundletool会在工具的目录中为您的设备创建 JSON 文件。然后,您可以将文件传递给bundletool以生成一组仅针对该 JSON 文件中描述的配置的 APK,如下所示

bundletool build-apks --device-spec=/MyApp/pixel2.json
--bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks

手动创建设备规范 JSON

如果您无法访问要为其构建目标 APK 集的设备(例如,如果您想在没有的设备上尝试您的应用),则可以使用以下格式手动创建 JSON 文件

{
  "supportedAbis": ["arm64-v8a", "armeabi-v7a"],
  "supportedLocales": ["en", "fr"],
  "screenDensity": 640,
  "sdkVersion": 27
}

然后,您可以将此 JSON 传递给bundle extract-apks命令,如上一节所述。

从现有 APK 集中提取特定于设备的 APK

如果您有现有的 APK 集,并且想要从中提取针对特定设备配置的 APK 子集,则可以使用extract-apks命令并指定设备规范 JSON,如下所示

bundletool extract-apks
--apks=/MyApp/my_existing_APK_set.apks
--output-dir=/MyApp/my_pixel2_APK_set.apks
--device-spec=/MyApp/bundletool/pixel2.json

测量 APK 集中 APK 的估计下载大小

要测量 APK 集中 APK 的估计下载大小(如通过网络压缩传输时的下载大小),请使用get-size total命令

bundletool get-size total --apks=/MyApp/my_app.apks

您可以使用以下标志修改get-size total命令的行为

表 2. get-size total命令的选项

标志 描述
--apks=path (必需) 指定要测量下载大小的现有 APK 集文件的路径。
--device-spec=path 指定设备规范文件(来自get-device-spec或手动构建)的路径,以用于匹配。您可以指定部分路径以评估一组配置。
--dimensions=dimensions 指定计算大小估计值时使用的维度。接受以下逗号分隔的列表:SDKABISCREEN_DENSITYLANGUAGE。要跨所有维度测量,请指定ALL
--instant 测量启用即时功能的 APK 的下载大小,而不是可安装 APK 的下载大小。默认情况下,bundletool测量可安装 APK 的下载大小。
--modules=modules 指定 APK 集中要考虑测量的模块的逗号分隔列表。bundletool命令会自动包含指定集的任何依赖模块。默认情况下,该命令会测量首次下载期间安装的所有模块的下载大小。

使用 SDK bundle 依赖项构建应用 bundle(实验性)

您可以使用命令行构建具有 Android SDK bundle (ASB) 依赖项的 Android 应用 bundle,并使用jarsigner对其进行签名。

每个应用 bundle 模块都包含一个模块协议缓冲区(.pb)文件:runtime_enabled_sdk_config.pb。此文件包含应用 bundle 模块依赖的 SDK 列表。有关此文件的完整定义,请参阅runtime_enabled_sdk_config.proto文件。

要使用 SDK bundle 依赖项构建应用 bundle,请按照有关使用 bundletool 构建应用 bundle部分中的步骤操作,并将runtime_enabled_sdk_config.pb文件添加到每个应用模块的 zip 文件中,其中包含已编译的代码和资源。

一些runtime_enabled_sdk_config.pb文件中值得注意的字段

  • 证书摘要:用于签署 SDK 的 APK 的密钥的证书的 SHA-256 摘要。这对应于Android SDK 归档格式SdkMetadata.pb文件中的证书。

  • 资源包 ID:将此 SDK 中的所有资源重新映射到的包 ID,用于生成用于将 SDK 嵌入到应用中的 APK。这可以实现向后兼容性。

SDK 只能出现在一个模块中。如果多个模块依赖于同一个 SDK,则应对该依赖项进行重复数据删除并将其移动到基本模块。不同的模块不能依赖于 SDK 的不同版本。

从具有 SDK bundle 依赖项的应用 bundle 生成 APK(实验性)

要从您的应用 bundle 生成 APK,请按照有关从应用 bundle 生成 APK 集部分或有关生成特定于设备的 APK 集部分中的步骤操作,并向bundletool build-apks命令提供应用依赖的 SDK。这些 SDK 可以以 SDK bundle 格式或 SDK 归档格式提供。

您可以通过添加--sdk-bundles标志以 SDK bundle 的形式提供 SDK,如下所示

bundletool build-apks --bundle=app.aab --sdk-bundles=sdk1.asb,sdk2.asb \
    --output=app.apks

您可以通过添加--sdk-archives标志以 SDK 归档的形式提供 SDK,如下所示

bundletool build-apks --bundle=app.aab --sdk-archives=sdk1.asar,sdk2.asar \
    --output=app.apks
为不支持 SDK 库的设备从具有 SDK bundle 依赖项的应用 bundle 生成 APK

Android 13 之前的设备不支持安装 SDK 库或在 SDK 运行时中运行它们。当您使用 bundletool build-apks 命令并带有 --sdk-bundles--sdk-archives 选项时,Bundletool 会隐藏向后兼容性的复杂性,并从同一个应用包生成多个 APK 集变体。这些多个变体针对具有不同功能的设备。

  • 对于较新的设备,有一个变体,其中 SDK 作为与应用分开的软件包安装,并且应用 APK 不包含任何 SDK 内容。
  • 对于较旧的设备,存在一个或多个变体,其中 SDK APK 作为附加的 APK 分割添加到应用 APK 集中。SDK APK 属于应用包。在这种情况下,SDK 运行时在设备上的应用运行时中进行模拟。

类似于您如何为没有 SDK 依赖项的应用包生成 APK,bundletool extract-apksbundletool install-apks 会从连接设备或提供的设备配置的最佳变体中返回一组经过过滤的 APK。

对于您只对为特定应用的旧设备生成来自 SDK 归档文件的 APK 分割的高级用例,请使用以下所示的 bundletool build-sdk-apks-for-app 命令

bundletool build-sdk-apks-for-app --app-properties=app-properties.json \
    --sdk-archive=sdk.asar --output=sdk.apks

app-properties 文件应包含 runtime_enabled_sdk_config.proto 文件中描述的字段。以下是 app-properties 文件的示例:

{
  "package_name": "com.my.app",
  "version_code": 1234,
  "min_sdk_version": 21,
  "resources_package_id": 0x7e
}

bundletool build-sdk-apks-for-app 命令会生成与应用包名称下的 SDK 内容相对应的应用 APK 子集。您可以将这些 APK 与包含应用内容的其他 APK 结合起来。例如,如果您分别构建它们并增量安装,并在不支持 SDK 运行时的设备上一起安装。

构建和测试 SDK 包(实验性)

您可以使用 bundletool 构建 ASB 并测试生成安装和分发所需的文件。

构建 SDK 包

您可以从命令行构建 ASB,并使用 jarsigner 对其进行签名。

要构建 SDK 包,请按照以下步骤操作:

  1. 按照与应用包相同的步骤,以 proto 格式生成 SDK 包的清单和资源

  2. 像处理应用模块一样,将 SDK 的编译代码和资源打包到一个基本 zip 文件中

  3. 生成一个 SdkModulesConfig.pb.json 文件和一个 SdkBundleConfig.pb.json 文件,使其格式与 Android SDK 包规范 中描述的格式匹配。

  4. 使用以下所示的 bundletool build-sdk-bundle 命令构建您的 ASB:

bundletool build-sdk-bundle --sdk-bundle-config=SdkBundleConfig.pb.json \
    --sdk-modules-config=SdkModulesConfig.pb.json \
    --modules=base.zip --output=sdk.asb

下表详细描述了使用 bundletool build-sdk-bundle 命令时可以设置的各种标志和选项。

表 3. bundletool build-sdk-bundle 命令的选项

标志 描述
--modules (必填) 您要从中构建最终 ASB 的模块文件。
--output (必填) 您希望构建 ASB 的路径。
--sdk-modules-config (必填) 描述 SDK 模块配置的 JSON 文件的路径。要了解如何格式化 JSON 文件,请参阅 Android SDK 包规范 部分。
--sdk-bundle-config 描述 SDK 包配置的 JSON 文件的路径。要了解如何格式化 JSON 文件,请参阅 Android SDK 包规范 部分。
--metadata-file 包含 ASB 元数据的文件。标志值的格式为 <bundle-path>:<physical-file>,其中 <bundle-path> 表示 SDK 包元数据目录内的文件位置,而 <physical-file> 是一个包含要存储的原始数据的文件。该标志可以重复使用。
--overwrite 如果设置了此选项,则会覆盖任何以前存在的输出。

从 SDK 包生成 APK

构建 ASB 后,您可以通过使用以下代码所示的 bundletool build-sdk-apks 命令生成其 APK 来在本地测试 SDK 包。

bundletool build-sdk-apks --sdk-bundle=sdk.asb --output=sdk.apks

bundletool 从您的 SDK 包生成 APK 时,该工具会将 APK 包含在一个名为“APK 集归档文件”的容器中,该容器使用 .apks 文件扩展名。bundletool 从 SDK 包生成一个针对所有设备配置的独立 APK。

如果要将 ASB 部署到设备,则还需要包含应用的签名信息,如下面的命令所示:

bundletool build-sdk-apks --sdk-bundle=sdk.asb --output=sdk.apks \
    --ks=keystore.jks \
    --ks-pass=file:/keystore.pwd \
    --ks-key-alias=KeyAlias \
    --key-pass=file:/key.pwd

下表详细描述了使用 bundletool build-sdk-apks 命令时可以设置的各种标志和选项。

表 4. bundletool build-sdk-apks 命令的选项

标志 描述
--sdk-bundle (必填) SDK 包的路径。必须具有扩展名 .asb
--output (必填) 默认情况下,您希望创建 APK 集归档文件的路径。或者,如果您使用 --output-format=DIRECTORY,则这是您希望存储生成 APK 的目录的路径。
--ks 您要用于签名生成 APK 的密钥库的路径。
--ks-key-alias 密钥库中要用于签名生成 APK 的密钥的别名。
--key-pass

密钥库中要用于签名生成 APK 的密钥的密码。

如果您以明文形式传递密码,则必须在值前面加上 pass:。例如,pass:qwerty。如果密码是文件的首行,则必须在值前面加上 file:。例如,file:/tmp/myPassword.txt

如果未设置此标志,则会尝试使用密钥库密码。如果失败,则命令行终端会提示您输入密码。

--ks-pass

要用于签名生成 APK 的密钥库的密码。

如果您以明文形式传递密码,则必须在值前面加上 pass:。例如,pass:qwerty。如果密码是文件的首行,则必须在值前面加上 file:。例如 file:/tmp/myPassword.txt

如果未设置此标志,则命令行终端会提示您输入密码。

--aapt2 要使用的 AAPT2 二进制文件的路径。
--output-format 生成 APK 的输出格式。默认情况下,此选项设置为 APK_SET,它会将 APK 输出到创建的 APK 集归档文件中。如果设置为 DIRECTORY,则会将 APK 输出到 --output 指定的目录中。
--verbose 如果设置了此选项,则会在标准输出中打印有关命令执行的额外信息。
--version-code SDK 版本代码。这是 Android 平台用于安装 APK 的版本代码,而不是 SDK 版本。此选项可以设置为任意值。如果未设置,则默认为 0。
--overwrite 如果设置了此选项,则会覆盖任何以前存在的输出。

部署、提取和测量 SDK APK 的大小

您可以按照应用使用的相同步骤将 APK 部署到连接的设备从现有的 APK 集提取特定于设备的 APK 以及测量 APK 集中 APK 的估计下载大小

从 SDK 包生成 SDK 归档文件

将 ASB 上传到您的分发渠道(例如 Google Play)后,ASB 会转换为 Android SDK 归档文件 (.asar),以便通过 Maven 分发给应用开发者。有关格式的更多详细信息,请参阅有关 SDK 归档文件格式规范 的部分。

构建 ASB 后,您可以使用以下代码所示的 bundletool build-sdk-asar 命令在本地测试 Android SDK 归档文件的生成。

bundletool build-sdk-asar --sdk-bundle=sdk.asb --output=sdk.asar \
    --apk-signing-key-certificate=keycert.txt

下表详细描述了使用 bundletool build-sdk-asar 命令时可以设置的各种标志和选项。

表 5. bundletool build-sdk-asar 命令的选项

标志 描述
--apk-signing-key-certificate (必填) SDK APK 签名证书的路径。这是与您在 build-sdk-apks 命令中用于签名 APK 的密钥对应的证书。
--output (必填) 您希望创建 .asar 文件的路径。
--sdk-bundle (必填) SDK 包的路径。必须具有扩展名 .asb
--overwrite 如果设置了此选项,则会覆盖任何以前存在的输出。

运行时启用 SDK 格式(实验性)

运行时启用 SDK 引入了两种 Android 文件格式:

Android SDK 包格式

SDK 包是运行时启用 SDK 的发布格式。它包含所有 SDK 代码和资源,包括 SDK 依赖的任何库的代码。它不包含 SDK 依赖的其他运行时启用 SDK 的代码和资源。

Android SDK 包 (ASB) 是一个带 .asb 扩展名的已签名 zip 文件。SDK 代码和资源在其组织方式上与 APK 中的类似。ASB 还包含几个配置文件,有助于生成可安装的 APK。

图 1. Android SDK 包的内容。

以下列表更详细地描述了一些 ASB 文件:

  • SdkBundleConfig.pb:一个以 proto 格式表示的配置文件,其中包含 SDK 依赖的运行时启用 SDK 列表。有关完整定义,请参阅 sdk_bundle_config.proto 文件。

  • modules.resm:一个包含生成 SDK APK 所需的所有数据的 zip 文件。

  • SdkModulesConfig.pb:一个以 proto 格式表示的配置文件。此文件包含 SDK 名称、版本以及框架 SDK 入口点的类名 (SandboxedSdkProvider)。有关完整定义,请参阅 sdk_modules_config.proto 文件。

  • base/:包含 SDK 代码和资源的单个模块。

    • manifest/:SDK 的清单文件,采用 proto 格式。
    • dex/:已编译的 DEX 格式代码。可以提供多个 DEX 文件。
    • res/lib/assets/:这些目录与典型 APK 中的目录相同。在生成 SDK 的 APK 时,这些目录中的路径将被保留。
    • root/:此目录存储稍后将重新定位到 SDK APK 根目录的文件。例如,它可能包含 SDK 使用 Class.getResource() 方法加载的基于 Java 的资源。此目录内的路径也将被保留。
  • BUNDLE-METADATA:此目录包含元数据文件,其中包含对工具或应用商店有用的信息。此类元数据文件可能包括 ProGuard 映射和 SDK 的 DEX 文件的完整列表。此目录中的文件不会打包到 SDK 的 APK 中。

Android SDK 归档格式

Android SDK 归档是 Maven 上支持运行时的 SDK 的分发格式。它是一个扩展名为 .asar 的 zip 文件。该文件包含应用构建工具生成依赖于支持运行时的 SDK 的 Android 应用包所需的所有信息。

图 2. Android SDK 归档包的内容。

以下列表更详细地描述了一些 Android SDK 归档文件。

  • SdkMetadata.pb:一个采用 proto 格式的配置文件,其中包含 SDK 名称、版本以及用于对为该 SDK 生成的 APK 签名的密钥的证书摘要。有关完整定义,请参阅 sdk_metadata.proto 文件。

  • modules.resm:一个 zip 文件,其中包含从 SDK 生成 APK 所需的所有数据。这与 Android SDK Bundle 中的 .resm 文件相同。

  • AndroidManifest.xml:SDK 的清单文件,采用文本 XML 格式。

其他资源

要了解有关使用 bundletool 的更多信息,请观看 应用包:使用 bundletool 和 Play Console 测试应用包