Android App Bundle 格式

Android App Bundle 是您上传到 Google Play 的一种文件(文件扩展名为 .aab)。

app bundle 是经过签名的二进制文件,可将应用的代码和资源组织到不同的模块中,如图 1 所示。各个模块的代码和资源的组织方式都与 APK 中的相似,之所以如此,是因为每个模块都可以作为单独的 APK 生成。然后,Google Play 会使用 app bundle 生成向用户提供的各种 APK,如基本 APK、功能 APK、配置 APK 以及多 APK(多 APK 适用于不支持拆分 APK 的设备)。以蓝色标识的目录(如 drawable/values/lib/ 目录)表示 Google Play 用来为每个模块创建配置 APK 的代码和资源。

app bundle 会将您的应用组织到不同的目录中,每个目录代表一个模块。在每个模块目录中,代码和资源的组织方式与典型的 APK 类似。

图 1. 包含一个基本模块、两个功能模块和两个资源包的 Android App Bundle 的内容。

以下列表更详细地介绍了 App Bundle 的部分文件和目录:

  • base/、feature1/ 和 feature2/:其中每个顶级目录都表示一个不同的应用模块。应用的基本模块始终包含在 App Bundle 的 base 目录中。不过,为每个功能模块的目录提供的名称由模块清单中的 split 属性指定。如需了解详情,请参阅功能模块清单
  • asset_pack_1/ 和 asset_pack_2/:对于需要大量图形处理的大型应用或游戏,您可以将资产模块化处理为资源包。资源包因体积上限较高而成为游戏的理想之选。您可以按照三种分发模式(即,安装时分发、快速跟进式分发和按需分发)自定义如何以及何时将各个资源包下载到设备上。所有资源包都在 Google Play 上托管并从 Google Play 提供。如需详细了解如何将资源包添加到您的 app bundle,请参阅 Play Asset Delivery 概览
  • BUNDLE-METADATA/:此目录包含元数据文件,其中包含对工具或应用商店有用的信息。此类元数据文件可能包含 ProGuard 映射和应用的 DEX 文件的完整列表。此目录中的文件未打包到您应用的 APK 中。
  • 模块协议缓冲区 (*.pb) 文件:这些文件提供了一些元数据,有助于向各个应用商店(如 Google Play)说明每个应用模块的内容。例如,BundleConfig.pb 提供了有关 bundle 本身的信息(如用于构建 app bundle 的构建工具版本),native.pbresources.pb 说明了每个模块中的代码和资源,这在 Google Play 针对不同的设备配置优化 APK 时非常有用。
  • manifest/:与 APK 不同,app bundle 将每个模块的 AndroidManifest.xml 文件存储在这个单独的目录中。
  • dex/:与 APK 不同,app bundle 将每个模块的 DEX 文件存储在这个单独的目录中。
  • res/、lib/ 和 assets/:这些目录与典型 APK 中的目录完全相同。当您上传 App Bundle 时,Google Play 会检查这些目录并且仅打包满足目标设备配置需求的文件,同时保留文件路径。
  • root/:此目录存储的文件之后会重新定位到包含此目录所在模块的任意 APK 的根目录。例如,app bundle 的 base/root/ 目录可能包含您的应用使用 Class.getResource() 加载的基于 Java 的资源。这些文件之后会重新定位到您应用的基本 APK 和 Google Play 生成的每个多 APK 的根目录。此目录中的路径也会保留下来。也就是说,目录(及其子目录)也会重新定位到 APK 的根目录。

拆分 APK 概览

提供经过优化的应用所需的一个基本组件就是 Android 5.0(API 级别 21)及更高版本上提供的拆分 APK 机制。拆分 APK 与常规 APK 非常相似,其中包含经过编译的 DEX 字节码、资源和 Android 清单。不过,Android 平台能够将安装的多个拆分 APK 视为一个应用。也就是说,您可以安装多个拆分 APK,它们共用代码和资源,并且在设备上看起来像是安装的一个应用。

拆分 APK 的好处是能够将单体式 APK 拆分为更小的独立软件包,这些软件包可“按需”安装在用户设备上。单体式 APK 是指一个 APK 中包含应用所支持的全部功能和设备配置对应的代码和资源。

例如,一个拆分 APK 可能包含只有少数用户需要的附加功能所对应的代码和资源,而另一个拆分 APK 则只包含特定语言或屏幕密度所对应的资源。这些拆分 APK 可以根据用户的请求或设备的需要单独下载和安装。

下面介绍可以一起安装在设备上以形成完整应用体验的不同类型的 APK。本页的后面几节将介绍如何配置应用项目以支持这些 APK。

  • 基本 APK:此 APK 中包含了所有其他拆分 APK 都可以访问的代码和资源,并提供应用的基本功能。当用户请求下载您的应用时,会首先下载并安装该 APK。这是因为只有基本 APK 的清单才包含关于应用的服务、内容提供方、权限、平台版本要求和对系统功能的依赖性的完整声明。Google Play 会根据项目的应用模块(即基本模块)为应用生成基本 APK。如果您想减小应用的初始下载大小,请一定要注意,此模块中包含的所有代码和资源都包含在应用的基本 APK 中。
  • 配置 APK:每个配置 APK 都包含针对特定屏幕密度、CPU 架构或语言的原生库和资源。当用户下载您的应用时,他们的设备只会下载并安装该设备对应的配置 APK。每个配置 APK 都是基本 APK 或功能模块 APK 的依赖项。也就是说,配置 APK 会随它们为之提供代码和资源的 APK 一起下载和安装。与基本模块和功能模块不同,您不需要为配置 APK 单独创建模块。如果您在为基本模块和功能模块组织管理配置专用的备用资源时遵循了标准实践,Google Play 会自动为您生成配置 APK
  • 功能模块 APK:每个功能模块 APK 都包含您使用功能模块进行了模块化处理的某项应用功能的代码和资源。您随后可以自定义如何以及何时将该功能下载到设备上。例如,使用 Play 核心库,可在将基本 APK 安装到设备上之后再按需安装某些功能,以向用户提供额外的功能。假设我们有一款聊天应用,它仅在用户想要拍摄并发送照片时才下载并安装该功能。由于功能模块在安装时可能不可用,因此您应将所有通用代码和资源包含在基本 APK 中。也就是说,您的功能模块应假定在安装时只有基本 APK 的代码和资源可用。Google Play 会根据项目的功能模块为应用生成功能模块 APK。

假设我们有一款包含三个功能模块并支持多种设备配置的应用。下面的图 1 展示了该应用的各个 APK 的依赖关系树可能是什么样子的。请注意,基本 APK 构成树的头部,所有其他 APK 都依赖于基本 APK。(如果您想知道这些 APK 的模块在 Android App Bundle 中的表示方式,请参阅 Android App Bundle 格式。)

基本 APK 位于树的头部,并有功能模块 APK 依赖于基本 APK。配置 APK 构成依赖关系树的叶节点,此类 APK 中包含了基本 APK 和各个功能模块 APK 的设备配置专用代码和资源。

图 1. 使用拆分 APK 构建的应用的依赖关系树

请注意,您无需自己构建这些 APK,Google Play 会根据您通过 Android Studio 构建的单个签名 app bundle 来为您完成构建。如需详细了解 app bundle 的格式和构建方式,请转到构建、部署和上传 Android App Bundle

搭载 Android 4.4(API 级别 19)及更低版本的设备

由于搭载 Android 4.4(API 级别 19)及更低版本的设备不支持下载和安装拆分 APK,因此 Google Play 会为这些设备提供名为 multi-APK 的单个 APK,该 APK 针对相应设备配置进行了优化。也就是说,multi-APK 提供完整的应用体验,但不包含不必要的代码和资源,例如用于其他屏幕密度和 CPU 架构的代码和资源。

但是,它们包含了应用所支持的所有语言的资源。例如,这让用户无需另外下载 multi-APK 即可更改应用的首选语言设置。

multi-APK 无法在以后按需下载功能模块。如需将功能模块包含在此 APK 中,必须在创建功能模块时停用按需选项或启用融合选项。

请注意,有了 app bundle,您无需为应用支持的每种设备配置分别构建、签署、上传和管理 APK。您仍然只需为整个应用构建和上传一个 app bundle,剩下的工作可交由 Google Play 处理。因此,无论您是否打算支持搭载 Android 4.4 或更低版本的设备,Google Play 都为您和您的用户提供了灵活的服务机制。

用户语言更改

通过 app bundle,设备只会下载运行应用所需的代码和资源。因此,对于语言资源,用户的设备只会下载与设备设置中当前所选的一种或多种语言相符的应用语言资源。

当用户在设备设置中切换语言时,Google Play 可能需要下载并安装一些额外的拆分 APK,然后应用才能以新语言显示。

切换语言后,Google Play 会尝试立即下载其他语言。如果用户设备处于离线状态、下载失败或者资源太大,Google Play 会在设备条件更有利时重新尝试在后台下载。在搭载 Android 9.0(API 级别 28)或更低版本的设备上,如果应用在安装新语言拆分 APK 期间在前台运行,则应用会被终止。

如果您的应用要求随时在设备上提供所有语言,您可以在构建配置中停用语言拆分

如果您的应用需要独立于设备设置中所选的用户语言下载其他语言(例如,实现应用内语言选择器),您可以使用 Play Core 库按需下载相应语言