bundletool

bundletool 是 Android Studio、Android Gradle 插件和 Google Play 用于构建 Android App Bundle 的底层工具。bundletool 可将 app bundle 转换为部署到设备的各种 APK。

Android SDK Bundle (ASB) 及其 APK 就是使用 bundletool 构建的。它还可以用作命令行工具,以便您自行构建 app bundle 和 SDK Bundle,以及为应用 APK 或支持运行时的 SDK 的 APK 重新创建 Google Play 服务器端 build。

下载 bundletool

如果您还没有下载 bundletool,请从 GitHub 代码库下载。

构建和测试 app bundle

您可以使用 Android Studio 或 bundletool 命令行工具来构建 Android App Bundle 文件,然后测试从该 app bundle 生成 APK。

构建 app bundle

请使用 Android Studio 和 Android Gradle 插件构建 Android App Bundle 文件并为其签名。但是,如果无法使用该 IDE(例如,因为您使用的是连续构建服务器),您也可以从命令行构建 app bundle 并使用 jarsigner 为其签名。

如需详细了解如何使用 bundletool 构建 app bundle,请参阅使用 bundletool 构建 app bundle

从 app bundle 生成一组 APK

构建 Android App Bundle 文件后,请测试 Google Play 使用该 Android App Bundle 文件生成 APK 的情形,以及这些 APK 部署到设备上之后的表现。

您可以通过以下两种方式测试 app bundle:

本部分将介绍如何使用 bundletool 在本地测试 app bundle。

bundletool 从 app bundle 生成 APK 后,它会将生成的 APK 纳入到一个名为“APK set archive”的容器中,该容器以 .apks 作为文件扩展名。如需从 app bundle 为应用支持的所有设备配置生成一组 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 构建的 app 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 如果您有多个已连接的设备,请使用此标志指定要部署应用的设备的序列号。
--device-spec=spec_json 提供 .json 文件的路径,该文件指定了您要针对其生成 APK 的设备配置。如需了解详情,请参阅有关如何生成并使用设备规范 JSON 文件的部分。
--mode=universal 将模式设置为 universal。如果您希望 bundletool 构建一个包含应用的所有代码和资源的 APK,以使该 APK 与应用支持的所有设备配置兼容,请使用此选项。

注意bundletool 仅包含功能模块,这些模块在通用 APK 中的对应清单中指定 <dist:fusing dist:include="true"/>。如需了解详情,请参阅功能模块清单

请注意,这些 APK 要比针对特定设备配置优化过的 APK 更大。但是,这些 APK 更便于与内部测试人员共享,例如想在多种设备配置上测试应用的测试人员。

--local-testing 启用 app 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 将在压缩后通过网络传送。如需估算这些 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 依赖项的 app bundle(实验性功能)

您可以从命令行构建包含 Android SDK Bundle (ASB) 依赖项的 Android App Bundle 文件,然后使用 jarsigner 为其签名。

每个 app bundle 模块都包含一个模块协议缓冲区 (.pb) 文件:runtime_enabled_sdk_config.pb。此文件列出了 app bundle 模块所依赖的 SDK。如需了解此文件的完整定义,请参阅 runtime_enabled_sdk_config.proto 文件。

如需构建包含 SDK Bundle 依赖项的 app bundle,请按照有关如何使用 bundletool 构建 app bundle 的部分中的步骤操作,并将 runtime_enabled_sdk_config.pb 文件添加到每个应用模块的 ZIP 文件(内含经过编译的代码和资源)中。

runtime_enabled_sdk_config.pb 文件中的一些重要字段:

  • 证书摘要:用于对 SDK 的 APK 进行签名的密钥证书的 SHA-256 摘要,与 Android SDK Archive 格式 SdkMetadata.pb 文件中的证书相对应。

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

一个 SDK 只能出现在一个模块中。如果多个模块依赖于同一 SDK,则应删除此依赖项的重复信息并将其移至基本模块。不同的模块不能依赖于不同版本的 SDK。

从包含 SDK Bundle 依赖项的 app bundle 生成 APK(实验性功能)

如需从 app bundle 生成 APK,请按照有关如何从 app bundle 生成一组 APK 的部分或有关如何生成一组设备专用 APK 的部分中的步骤操作,并向 bundletool build-apks 命令提供应用所依赖的 SDK。这些 SDK 可以采用 SDK Bundle 格式或 SDK Archive 格式提供。

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

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

您可以通过添加 --sdk-archives 标记以 SDK Archive 的形式提供 SDK,如下所示:

bundletool build-apks --bundle=app.aab --sdk-archives=sdk1.asar,sdk2.asar \
    --output=app.apks
针对不支持 SDK 库的设备,从包含 SDK Bundle 依赖项的 app bundle 生成 APK

搭载 Android 13 之前版本的设备不支持安装 SDK 库或在 SDK 运行时中运行 SDK 库。当您使用 --sdk-bundles--sdk-archives 选项运行 bundletool build-apks 时,bundletool 可以避免向后兼容的复杂性,并通过同一 app bundle 生成 APK 集的多个变体。多个变体以具有不同功能的设备为目标:

  • 还有适用于新款设备的变体,其中 SDK 作为独立于应用的软件包安装,并且应用 APK 不包含任何 SDK 内容。
  • 有一个或多个适用于旧款设备的变体,其中 SDK APK 会作为额外的 APK 拆分添加到应用 APK 集中。SDK APK 属于应用软件包。在这种情况下,在设备上的应用运行时模拟 SDK 运行时。

与为没有 SDK 依赖项的 app bundle 生成 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 Bundle(实验性功能)

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

构建 SDK Bundle

您可以从命令行构建 ASB,然后使用 jarsigner 为其签名。

如需构建 SDK Bundle,请按以下步骤操作:

  1. 按照与 app bundle 相同的步骤,为 SDK Bundle 生成 proto 格式的清单和资源

  2. 与应用模块一样,将 SDK 经过编译的代码和资源打包到一个基础 ZIP 文件中

  3. 生成与 Android SDK Bundle 规范中所述格式一致的 SdkModulesConfig.pb.json 文件和 SdkBundleConfig.pb.json 文件。

  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 Bundle 规范部分。
--sdk-bundle-config 指向描述 SDK Bundle 配置的 JSON 文件的路径。如需了解如何设置 JSON 文件的格式,请参阅 Android SDK Bundle 规范部分。
--metadata-file 包含 ASB 元数据的文件。标志值的格式为 <bundle-path>:<physical-file>,其中 <bundle-path> 表示该文件在 SDK Bundle 元数据目录中的位置,<physical-file> 是包含要存储的原始数据的现有文件。该标志可以重复使用。
--overwrite 设置后,此选项便会覆盖所有先前的已有输出。

从 SDK Bundle 生成 APK

构建 ASB 后,您可以通过使用 bundletool build-sdk-apks 命令生成 SDK Bundle 的 APK 在本地对该 SDK Bundle 进行测试,如以下代码所示:

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

bundletool 从 SDK Bundle 生成 APK 时,该工具会将这些 APK 纳入到一个名为“APK set archive”的容器中,该容器以 .apks 作为文件扩展名。bundletool 会从 SDK Bundle 中生成一个针对所有设备配置的独立 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 Bundle 的路径。扩展名必须为 .asb
--output (必需)默认情况下,要在其中创建 APK set archive 的路径。或者,如果您使用 --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 set archive 中。如果设置为 DIRECTORY,则会将 APK 输出到 --output 指定的目录中。
--verbose 设置后,此选项便会在标准输出内容中输出有关命令执行的额外信息。
--version-code SDK 版本代码。这是 Android 平台安装 APK 所用的版本代码,而不是 SDK 版本。此选项可设置为任意值。如果未设置,则默认为 0。
--overwrite 设置后,此选项便会覆盖所有先前的已有输出。

部署和提取 SDK APK 以及估算其大小

您可以按照针对应用将 APK 部署到连接的设备从现有的 APK 集中提取设备专用 APK 以及估算 APK 集中 APK 的下载大小的相同步骤操作。

从 SDK Bundle 生成 SDK Archive

当您将 ASB 上传到分发渠道(例如 Google Play)后,该 ASB 会转换为 Android SDK Archive (.asar),以便通过 Maven 分发给应用开发者。如需详细了解此格式,请参阅有关 SDK Archive 格式规范的部分。

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

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 Bundle 的路径。扩展名必须为 .asb
--overwrite 设置后,此选项便会覆盖所有先前的已有输出。

支持运行时的 SDK 格式(实验性功能)

支持运行时的 SDK 引入了两种 Android 文件格式:

Android SDK Bundle 格式

SDK Bundle 是支持运行时的 SDK 的发布格式,其中包含所有 SDK 代码和资源(包括 SDK 所依赖的库中的代码),但不包含 SDK 所依赖的其他支持运行时的 SDK 的代码和资源。

Android SDK Bundle (ASB) 是一种已签名 ZIP 文件,扩展名为 .asb。SDK 代码和资源在该文件中的组织方式与 APK 中的类似。ASB 还包含多个有助于生成安装版 APK 的配置文件。

图 1. Android SDK Bundle 的内容。

以下列表更详细地介绍了一些 ASB 文件:

  • SdkBundleConfig.pb:proto 格式的配置文件,其中列出了 SDK 所依赖的支持运行时的 SDK。如需了解完整定义,请参阅 sdk_bundle_config.proto 文件。

  • modules.resm:包含从 SDK 生成 APK 所需全部数据的 ZIP 文件。

  • SdkModulesConfig.pb:proto 格式的配置文件,其中包含框架 (SandboxedSdkProvider) 的 SDK 入口点的 SDK 名称、版本以及类名称。如需了解完整定义,请参阅 sdk_modules_config.proto 文件。

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

    • manifest/:proto 格式的 SDK 清单。
    • 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 Archive 格式

Android SDK Archive 是 Maven 上支持运行时的 SDK 的分发格式。这是一种文件扩展名为 .asar 的 ZIP 文件,其中包含应用构建工具生成依赖于支持运行时的 SDK 的 Android App Bundle 文件所需的全部信息。

图 2. Android SDK Archive Bundle 的内容。

以下列表更详细地介绍了一些 Android SDK Archive 文件:

  • SdkMetadata.pb:proto 格式的配置文件,其中包含 SDK 名称、版本以及用于对此 SDK 所生成 APK 进行签名的密钥的证书摘要。如需了解完整定义,请参阅 sdk_metadata.proto 文件。

  • modules.resm:包含从 SDK 生成 APK 所需全部数据的 ZIP 文件。这与 Android SDK Bundle 中的 .resm 文件相同。

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

其他资源

如需详细了解如何使用 bundletool,请观看 App Bundle:使用 bundletool 和 Play 管理中心测试 app bundle