Android应用在Google Play上架时有明确的基础包体积限制,超过AAB格式150MB的部分必须通过Asset Packs资源包来分发。这套机制官方名称叫Play Asset Delivery,简称PAD,它把纹理、音频、3D模型、机器学习模型等大型文件从主包中剥离出来,由Google Play在合适的时机自动下发给用户。对游戏和富媒体应用来说,这是绕不开的技术方案。

三种分发模式怎么选
Play Asset Delivery提供了三种资源分发模式,选择正确的模式直接决定用户的下载体验。第一种是install模式,资源包会在安装APK的同时一起下载,用户安装完成后资源就已经就绪。适合那些应用一启动就必需的素材,比如游戏的新手关卡资源、启动画面的高清贴图等。这种模式对用户来说最无感,但也意味着安装包总下载体积变大。
第二种是fast-delivery模式,也叫快速跟进型,资源会在应用安装完成后立即在后台开始下载,用户可以边用边等。适合短时间内就会用到的资源,比如游戏第二关以后的场景素材。第三种是on-demand按需模式,资源只在代码主动请求时才触发下载,这是最节省用户流量和存储空间的方式,适合可选关卡、季节活动内容、大型AI模型文件等。
实际项目中的常见做法是组合使用:把首日必需的资源放进install模式,把近期会用到的放进fast-delivery,其余全部走on-demand。需要注意的是,每个Asset Pack最大2GB,单个应用最多可以有50个资源包,这个容量上限对绝大多数场景都足够宽裕。
工程配置与资源打包
Asset Packs基于Android App Bundle工作,工程结构上需要在主模块旁边创建资源包模块。以Gradle构建为例,先在项目根目录创建一个名为level_assets的资源目录,结构如下:
level_assets/
├── build.gradle
└── src/main/assets/
└── level textures.../资源包模块的build.gradle需要引入play asset delivery插件并声明分发模式:
// level_assets/build.gradle
apply plugin: 'com.android.asset-pack'
assetPack {
packName = "level_assets"
dynamicDelivery = {
deliveryType = "on-demand"
}
}然后在主模块的build.gradle中通过assetPacks属性关联这个资源包:
// app/build.gradle
android {
assetPacks = [":level_assets"]
}settings.gradle中记得include资源包模块。完成配置后,用Android Studio的Generate Signed Bundle生成AAB,资源文件会按packName自动归档到对应的资源包中。代码里访问这些资源时,不能再用常规的assets路径,而是要通过AssetManager的open方法配合Play Asset Delivery返回的路径来读取,这一点是新手最容易踩坑的地方。
运行时下载与状态管理
对于on-demand和fast-delivery模式的资源包,应用必须在运行时主动请求下载并监听状态变化。官方推荐使用Play Asset Delivery库,核心类是AssetPackManager。下面是一段典型的请求与监听代码:
AssetPackManager manager = AssetPackManagerFactory
.getInstance(getApplicationContext());
AssetPackStates states = manager.getPackStates(
Collections.singletonList("level_assets")).get();
AssetPackState packState = states.packStates().get("level_assets");
if (packState.status() == AssetPackStatus.NOT_INSTALLED) {
// 发起异步下载请求
manager.fetch(Collections.singletonList("level_assets"));
}
// 注册状态监听
manager.registerListener(state -> {
long total = state.totalBytes();
long downloaded = state.bytesDownloaded();
if (state.status() == AssetPackStatus.DOWNLOADING) {
// 更新下载进度条
int progress = (int) (downloaded * 100 / total);
progressBar.setProgress(progress);
} else if (state.status() == AssetPackStatus.COMPLETED) {
// 下载完成,可以加载资源了
loadLevelResources();
} else if (state.status() == AssetPackStatus.FAILED) {
// 下载失败,根据errorCode做重试或提示
retryWithBackoff(state.errorCode());
}
});资源下载完成后,通过getAssetLocation获取资源的本地路径,再用AssetManager打开文件流:
AssetPackLocation location = manager
.getPackLocation("level_assets");
if (location != null) {
String assetsPath = location.assetsPath();
AssetManager am = getAssets();
InputStream is = am.open("level_textures/bg.png");
// 正常读取流数据
}状态机需要处理的情况不少:下载中、下载暂停(比如用户切到蜂窝网络)、需要用户确认的Wi-Fi下载、传输失败等。建议把状态处理封装成独立的模块,用LiveData或Flow向UI层暴露进度,避免在Activity里堆满回调逻辑。另外用户随时可能清除应用数据,on-demand包会被删除,应用启动时应该主动检查关键资源包的可用性。
本地测试与上架注意事项
PAD的完整流程依赖Google Play服务,本地开发时无法直接体验真实下载。官方提供了两种测试手段。第一种是使用bundletool在本地生成并模拟安装,通过build-apks命令带上local-testing参数生成测试包:
java -jar bundletool.jar build-apks --bundle=app.aab --output=local_test.apks --local-testing
使用local-testing生成的包在安装时,资源包会直接从本地读取而绕过Play商店,可以快速验证资源路径和加载逻辑是否正确。但要注意这种模式下on-demand包的下载速度模拟和真实环境有差异,流量计费、断点续传等逻辑还是需要结合内部测试轨道验证。
第二种方式是把AAB上传到Google Play的内部测试轨道,邀请测试人员通过真实商店渠道安装,这是最接近线上表现的验证方式。上架前还有几个细节值得留意:资源文件名避免使用中文和特殊字符,防止路径解析异常;大型资源建议做好版本管理,因为资源包更新走的是AAB整体更新流程,频繁更新会让用户重新下载变更的资源;对于游戏类应用,如果基础包加资源包总体积较大,最好在应用内提供资源清理入口,帮用户释放已通关内容的存储空间。
最后提醒一点,国内渠道分发的应用无法使用Play Asset Delivery,这套方案只适用于Google Play生态。如果产品面向多渠道发布,建议把资源加载层抽象出来,国内渠道走传统的拆包或热更新方案,海外渠道走PAD,共用同一套上层资源管理接口,降低维护成本。
Asset PacksPlay Asset Delivery资源分发修改时间:2026-09-11 06:11:23