场景

Android 12 引入的“边玩边下”(Play as you download)能力,是指应用(尤其是游戏)在仅下载部分资源的情况下即可启动运行,同时剩余资源在后台持续下载。

该机制显著缩短了用户等待时间,使用户可以在数秒内进入应用,并在使用过程中逐步加载后续内容,从而提升整体体验的流畅性。

运行时流程

用户点击安装
↓
Play 生成最小启动集(base + 必要 asset pack)
↓
Incremental install 开始
↓
App 启动(部分文件缺失)
↓
运行时触发按需加载
↓
后台继续下载剩余资源

该流程的核心在于:系统并不等待完整下载完成,而是通过“最小可运行集 + 增量文件访问机制”,使应用在资源不完整的情况下即可启动,并在运行过程中逐步补齐所需数据。

将应用从“完整安装后运行”转变为“按需加载、逐步完整”的执行模型

实现思路

为了实现“边玩边下”,Android 在系统、分发和应用多个层面进行了协同设计,整体可以分为四个关键部分:

系统与运行时(源码层)

  • 引入对 增量安装(Incremental Installation / Incremental FS) 的支持,允许 APK/资源未完全下载时就可被访问和执行。
  • ART / PackageManager 做了适配,ART 支持“边加载边执行”,优先加载关键代码与资源。文件系统层支持按需读取,缺失部分后台拉取。

应用打包与构建工具(开发侧)

  • Android App Bundle(AAB)成为标准,支持将应用拆分为多个模块(base + asset packs)。
  • 引入 Play Asset Delivery(PAD) 和 Play Feature Delivery(PFD),开发者可以标记“首包必需资源”和“后续下载资源”。
  • 构建工具(Gradle / bundletool)支持资源分片、优先级声明和按需分发。

Google Play 商店(分发侧)

  • Play Store 支持“边下载边启动”,优先下发启动所需的最小资源集。
  • 后台智能调度资源下载顺序(例如先下首关内容)。

应用设计与体验层(开发人员规范)

  • 游戏需要按关卡/资源分块设计,例如前几关一个 asset 文件夹
  • 每次请求需要判断资源是否存在,并设计资源请求

系统与运行时机制

核心目标:在应用或资源尚未完全下载的情况下,实现应用可启动、可访问、按需加载,从而支持“边下载边运行”的流式安装体验。

Incremental Installation 增量安装

Android 引入 Incremental Installation 机制,使应用在 APK 未完全下载完成时即可被安装和启动。

  • PackageManager 支持流式安装(streamed install)
  • 安装过程不再依赖完整 APK 文件

Incremental FS

应用在文件尚未完全下载时就能被访问和执行。

实现方法

Incremental FS 会将文件拆分为固定大小的 block(通常为 4KB 级别),并通过内核拦截文件读取行为实现按需加载:

  1. App 启动,访问 APK / 资源文件
  2. read() 调用进入 VFS
  3. 由 Incremental FS 接管
  4. 判断目标 block 是否已就绪:
  • 已存在 → 直接返回数据
  • 未存在 → 阻塞当前 read,请求 Data Loader 加载

Data Loader(数据加载器)

其作用为根据请求下载缺失的 block 并写回 Incremental FS。

  • Data Loader 通常由 Google Play 驱动,实现网络下载与数据回填
  • 下载的数据会经过 hash 校验(基于 Merkle Tree),确保数据完整性

应用打包与分发机制

核心目标:通过模块化拆分应用和资源,实现按需下载与按需交付,使应用能够快速启动、减小首包体积,并支持后续功能和资源动态获取。

AAB基础格式

AAB 的核心作用,是将应用从“单一安装包”转变为“可按需组合的模块集合”,允许在分发阶段根据设备和场景动态生成安装内容。

AAB 可以将应用拆分为:

  • base module:应用启动和核心流程所需的基础模块
  • feature modules:可选功能模块
  • asset packs:大型资源包,如纹理、音频、地图、视频、关卡数据等

实际结构:

MyGame.aab/
├── base/
├── feature_login/
├── feature_ar/
├── asset_pack_level1/
├── asset_pack_hd_textures/
├── BUNDLE-METADATA/
└── BundleConfig.pb
  • base/:启动所需的核心模块
  • feature_XXX/:可选功能模块,通过 PFD 动态下载
  • asset_pack_XXX/:大资源包,通过 PAD 管理
  • BUNDLE-METADATA/:构建和签名信息
  • BundleConfig.pb:bundletool 配置文件,描述拆分和分发策略

PFD(Play Feature Delivery)

Play Feature Delivery 的核心目标,是把应用中的“功能能力”拆分为多个可独立交付的 feature 模块。并且要求 feature 模块之间尽量解耦、避免相互强依赖。并且要求:

  • 每个模块围绕一项清晰功能组织
  • 可按条件、按需或安装时下发
  • 首包中只保留最基础、最常用的功能
  • 后续模块在用户真正需要时再交付

实际结构:

feature_login/
├── manifest/
├── dex/
├── lib/
├── res/
├── assets/
└── resources.pb
  • manifest/:模块的 AndroidManifest.xml,描述模块入口、权限等
  • dex/:编译后的代码(classes.dex)
  • lib/:模块依赖的原生库(.so)
  • res/:编译后的资源(布局、字符串、图片等)
  • assets/:模块的原始资源文件(JSON、Shader、配置等)
  • resources.pb:资源表的 protobuf 文件,bundletool 在构建和拆分时使用

PAD(Play Asset Delivery)

用于大型资源的分包与动态加载:

  • 将资源划分为多个 asset pack(如按关卡划分)
  • 当前资源使用过程中可后台下载后续资源
  • 应用需在访问前确认资源是否已就绪

实际结构:

asset_pack_level1/
├── assets/
│   ├── level1_map.dat
│   ├── level1_texture.png
│   └── audio/
│       ├── bgm_level1.mp3
│       └── sfx_jump.wav
└── pack_metadata/
    ├── pack_version.pb
    └── pack_status.pb
  • assets/ :存放实际游戏资源,运行时通过 Play Core API 按需加载
  • pack_metadata/:存放资源包管理信息

分发模式

通过 Dynamic Delivery,可以将PAD和PFD按照三种分发模式(即安装时分发、快速跟进式分发和按需分发)自定义如何以及何时将各个资源包下载到设备上。

  • install-time:随应用安装时分发,会增大商店显示的应用体积,用户无法修改或删除。
  • fast-follow:应用安装后自动下载,不阻塞应用启动,不增大商店显示的应用体积。
  • on-demand:应用运行时按需下载,不增大商店显示的应用体积,文件位置不固定且可能被用户或系统移动/删除,应视为只读。

Google Play 商店(分发侧)

Play Store 会基于 AAB 结构生成 最小可运行集(base + 必需 asset packs)

在下载过程中采用 优先级调度策略:

  • 优先:启动路径资源(UI、首关)
  • 次级:短期会访问的资源
  • 延后:后续关卡/低频资源

下载顺序是 动态调整的(基于设备状态/网络/用户行为)