AAB 结构详解

说实话,刚开始接触 AAB 的时候我也挺懵的。APK 就是一个大压缩包,里面啥都塞一块。但 AAB 不一样,它更像一个“半成品”——把模块拆得干干净净,交给 Google Play 去拼装。今天我们就好好拆一拆这个 .aab 文件,看看里面到底长什么样。

目录结构概览

你把 .aab 文件后缀改成 .zip,解压出来,会看到下面这棵目录树。我自己第一次解压完愣了一下——怎么没有 classes.dex?嗯,因为它藏在更深的模块里。

myapp.aab/
├── base/
│   ├── dex/
│   │   └── classes.dex
│   ├── res/
│   ├── lib/
│   ├── manifest/
│   │   └── AndroidManifest.xml
│   └── assets/
├── feature1/
│   ├── dex/
│   ├── res/
│   ├── lib/
│   ├── manifest/
│   └── assets/
├── feature2/
│   └── ...
├── BundleConfig.pb
└── BundleMetadata.pb

根目录下最主要的几个模块目录,就是 base、feature… 每个模块都像一个小型的 APK 切片。我习惯把 base 看作“必装部分”,其他 feature 是“可选零件”。

核心要点:AAB 中每个模块独立打包,最终由 Play 商店按需组合成 APK 分发给用户。

base 模块——地基

base 模块是整个应用的骨架。没有它,app 启动不了。里面包含所有语言的字符串、所有 density 的资源、通用代码库、主 Manifest。说白了,你 app 的“最小运行集”全在这了。

我记得有一次把某个第三方 SDK 的 so 库放到了 feature 模块里,结果启动时直接崩溃——因为 base 模块里没有那套 native 库。所以我的建议是:

  • 所有 必须立即执行 的代码放 base
  • 所有 所有语言/分辨率 的资源放 base
  • 主 Activity、Application 类放 base

个人习惯:我会在 base 模块的 build.gradle 里显式声明 dist:install-time,确保它永远随安装包下发。

Feature 模块——按需投放

Feature 模块是 AAB 最具魅力的地方。它可以做到“用到才下载,不用就省钱”。比如一个购物 app 里,“直播购物”功能可能只有 30% 的用户用,那你就可以把它做成 feature 模块,通过 on-demand 或 conditional 交付。

它的目录结构和 base 几乎一样,区别在于 Manifest 里多了一个 <dist:module> 标签:

<dist:module
    dist:type="feature"
    dist:title="@string/live_module">
    <dist:delivery>
        <dist:on-demand />
    </dist:delivery>
    <dist:fusing dist:include="true" />
</dist:module>

你看,dist:on-demand 代表这个模块不随安装包一起下载,用户点击直播入口时,后台调用 Play 的 API 才拉下来。这里有个坑——我曾经把 dist:fusing include 设成了 false,结果有些低版本手机装完根本找不到那部分功能。嗯,不懂的话先保持 true 最安全。

模块化概念与配置

既然有了 base 和 feature,那它们之间怎么互相引用?你可以在 feature 模块的 build.gradle 里用 implementation project(':base') 来依赖基础代码。但不能反过来——base 不能依赖 feature,否则就破坏了按需加载的设计思想。

模块类型交付时机依赖关系
base安装时必装可依赖公共库,不依赖 feature
feature安装时 / 按需 / 条件可依赖 base 及其他 feature(需配置)

我个人强烈建议你一开始就把模块化结构规划好。别等代码写了几万行再拆,那时候你会欲哭无泪的。

我曾经犯过的错:把大量公共资源(比如颜色值、字符串)放在 base 模块里,但后来 feature 越来越多,每个 feature 又要改那几个颜色,结果 base 频繁更新,用户得重新下载整个包。更好的做法是把这些常量抽成独立库模块(library module),所有功能模块再去依赖它。

AAB 结构图

AAB 模块结构关系图 AAB 模块结构关系图 .aab 包 (Android App Bundle) base 模块 • 主 Activity / Application • 所有语言 / 分辨率资源 • 核心代码 & Manifest feature 模块 • 可选功能 (直播 / 地图 / …) • 自身资源 & 代码 • 独立的 Manifest 交付方式 install-time | on-demand | conditional feature 依赖 base 依赖 注意 base 不依赖 feature

这张图把 base、feature、交付方式的关系串起来了。你注意看:feature 可以依赖 base,但不能反着来。另外,每个 feature 模块还能设置自己的交付时机,所以你的 app 体积可以做到极度精准控制。

小结一下

刚才我们走了一遍 AAB 的内部结构:base 是骨架,feature 是可选装配件,每个模块都有自己的 Manifest 和资源。这种设计让 Google Play 能为你量身定做 APK,用户下载安装包就只拿到他那一份。