一、前言
Google Play发布应用,只支持上传aab格式文件。在之前,Google Play对上传apk文件限制大小不超过150MB,对于新的aab格式文件,也要求生成的目标apk不超过150MB(GooglePlay后台使用bundletool生成apk文件,更多关于bundletool的介绍和使用,请参考:bundletool 工具使用详解),如果发布的是游戏,Google Play也已经不再支持旧版的扩展文件(OBB文件),但是游戏可能会需要大量的游戏资源一并发布,于是Google就推出了资产分发的功能,这样一来,就可以实现超过150MB的单个aab文件上传到Google Play,并且使得生成的单个基础apk不超过150MB。Play资产分发提供了比较灵活的分发模式、自动更新、压缩和增量修补功能,重要的是这些还是免费的。使用 Play资产分发,所有的资源包都在Google Play上托管和提供,因此开发者无需内容分发网络向玩家提供游戏资源。
Play资产分发使用资源包的形式,资源包由资源(如纹理、着色器、声音等)组成,但是其中不可包含可执行的代码
注意事项:使用Play资产分发,不允许资源中包含可执行代码
二、Play资产分发的模式
Play资产分发可以分为三种模式,每种模式的分发时机和资源加载方式都有所不同。
2.1 安装时分发(install-time)
顾名思义,安装时分发就是资源包在用户安装应用时(下载)分发。这些资源包以拆分 APK(APK 集合的一部分,资源包也会生成一个apk文件)的形式提供。它们也称为“预先”资源包;安装时分发的一个好处就是可以在应用启动时立即使用这些资源包,而无需等待资源的下载。这些资源包会增加 Google Play 商店上列出的应用大小,用户在安装应用时同时下载安装,用户无法修改或删除这些资源包。更新应用时,安装时分发的资源包也会作为基础应用更新的一部分进行更新(开发者无需执行任何操作)。
2.2 快速跟进分发(fast-follow)
快速跟进分发,资源包会在用户安装应用后立即自动下载;用户无需打开应用即可开始 fast-follow 下载(下载由GooglePlay商店完成)。此类下载不会阻止用户访问应用。这些资源包也会增加 Google Play 商店上列出的应用大小。
2.3 按需分发(on-demand)
按需分发,也就是资源包会在应用运行时按需下载资源包。用户首次只下载安装基础apk,在程序运行过程中,根据场景和功能,按需下载对应的资源包。这些资源包不会增加 Google Play 商店上列出的应用大小。
Google Play 商店会以归档文件(而非拆分 APK)的形式提供配置为快速跟进分发和按需分发的资源包。这些资源包随后会在应用的内部存储空间中展开。您可以使用 Play Core API 查询以这l两种方分发式提供的资源包的位置。应用无法假设这些文件的存在和其存储位置,因为它们可能会被用户删除,或由 Play Core SDK 在游戏会话之间移动。尽管这些文件可由应用写入,您也应将其视为只读文件,因为资源包补丁程序依赖于这些文件的完整性。
对于快速跟进分发和按需分发资源包的应用更新,则遵循以下步骤:
- 系统将应用的补丁程序(包括所有资产)下载到设备上的安全位置。
- 更新应用二进制文件;这包括所有安装时分发的资源包。
- 之前下载的所有资源包均变为无效。
- 将资产的补丁程序复制并应用到存储在应用内部存储空间中的资产。
三、Google Play下载大小上限
资产分发的资源包因具有较高的大小上限而成为大型游戏的理想之选:
- 每个快速跟进分发和按需分发资源包的下载大小上限为 512 MB。
- 所有 安装时分发资源包的总下载大小上限为 1 GB。
- 一个 Android App Bundle 中的所有资产资源包的总下载大小上限为 2 GB。
- 一个 Android App Bundle 中最多可以使用 50 个资源包。
四、安装时分发(install-time)详解
安装时分发是最简单的一种,你无需对应用做任何更改即可实现。应用在下载安装时,会将安装时分发的资产包一并安装,分发的资源包在Assets资产中,应用可以直接通过 AssetManager
资产访问api对资源进行访问。虽说不需要对应用做任何更改,但前提是你的应用原本是主将资源放在Assets资产中(如果不是,则需要修改资源访问加载的代码)。另外,项目也需要做相应的配置变更,生成aab时将会为安装时分发的资源包生成单独的apk。下面我们来详细介绍一下步骤:
注意事项:配置安装时分发,需要项目中的Android Gradle 插件的版本为 4.0.0 或更高版本。可在项目的根目录下
build.gradle
文件检查项目中的Android Gradle 插件的版本。
4.1 创建产资源包模块
首先,需要新建一个模块,用来存放需要在安装时分发的资产资源。下面将详细介绍配置步骤:
- 在项目的顶级目录中,为资源包创建一个目录,此目录以资产资源包名称命名,资源包名称必须以字母开头,并且只能包含字母、数字和下划线。
- 在创建的资源包目录中,创建一个
build.gradle
文件。在配置文件中引入com.android.asset-pack
插件,并指定资源包的名称以及分发类型。如下示例:
// 资产资源包目录下的 build.gradle 配置文件
plugins {
id 'com.android.asset-pack' // 插件名称
}
assetPack {
packName = "asset_res_pack" // 指定资产资源包名称(资源目录会以此命名)
dynamicDelivery {
deliveryType = "install-time"//指定分发类型,install-time 即为安装时分发,可配置类型有[ install-time | fast-follow | on-demand ],其他类型以后再进行介绍
}
}
- 在项目的应用级
build.gradle
配置文件中,在android
块内部添加项目中每个资源包的名称,如下所示:
// 在应用级 build.gradle 配置文件中
android {
...
assetPacks = [":asset_res_packe"] // 指定资源包名称,如果有多个资源包,可在数组中添加多个,用半角逗号隔开
}
- 在项目级的
settings.gradle
配置文件中定义资源包模块,如下所示
// 在项目级的 settings.gradle 配置文件中定义资源包模块
include ':assets_res_pack'
4.2 添加资产资源
接下来,就需要将安装时分发的资产,添加到新建的模块中。
- 在新建资源包目录中,创建
src/main/assets
子目录。 - 将需要安装时分发的资产资源(原应用级
src/main/assets
目录下的资产资源),移动到新建的资源包目录下对应的子目录中。此时目录结构大致如下:
|-Project-Root/
|-build.gradle
|-settings.gradle
|-app/
|-asset_res_packe/
|-build.gradle
|-src/
|-main/
|-assets/
|-asset-resource-directories/(资产资源目录)
4.3 构建Android App Bundle(aab)
在生成的aab文件中,每个资产资源包都会在根目录下以资源包名为目录名称新建一个目录,如下图所示:
asset_res_pack
目录为资源包目录,在资源包目录内部,主要有两部份内容:
AndroidManifest.xml
清单文件(此文件是构建aab时自动生成),所在目录为asset-pack-name/manifest/AndroidManifest.xml
,清单文件中主要是配置资源包的标识符和分发模式。如下示例:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.rastargame.sdk.oversea.demo"
platformBuildVersionCode="31"
platformBuildVersionName="12"
split="asset_res_pack"
android:compileSdkVersion="31"
android:compileSdkVersionCodename="12" >
<dist:module dist:type="asset-pack" > <!-- 资源包类型,asset资产资源包 -->
<dist:fusing dist:include="true" />
<dist:delivery>
<dist:install-time /> <!-- 分发模式:安装时分发 -->
</dist:delivery>
</dist:module>
</manifest>
- 资产资源文件,这些资源文件存放在
asset-pack-name/assets/your-asset-directories
内部,内部的资源文件会在安装时同时安装到对应的asset资产目录中,程序通过AssetManager
API访问相应目录下的资源。
4.4 资源访问
安装时分发(install-time)是最简单的一种分发模式,无需借助特定的API库(如:Play Asset Delivery 库),使用原生的 AssetManager
API 即可访问资产资源。如下示例:
final AssetManager assetManager = getAssets();
try {
String [] rootFiles = assetManager.list("text/");
for(int i = 0; i < rootFiles.length; i++) {
LogUtils.e(rootFiles[i]);
}
} catch (Exception e) {
e.printStackTrace();
LogUtils.e(e.toString());
}
资源访问效果(成功读取资源文件列表):
4.5 本地测试
对于安装时分发的资源包,本地测试也是相当简单,只需要使用bundletool工具,对构建的aab生成apk集合(.apks),安装到设备中,测试资源包中的资源是否可以正常加载。
说明:本文中bundletool命令,已添加环境变量,对于没有添加环境变量,请使用
java -jar bundletool.jar
命令执行对应的 jar 文件。更多关于bundletool的使用,请参考:bundletool 工具使用详解
- 使用bundletool从aab文件生成apk集合(.apks),如下示例:
bundletool build-apks --bundle=demo-en-release.aab --output demo-en-local-test.apks --local-testing
说明:
--local-testing
参数是用来标记apk集合是用于本地测试。请参考:bundletool 工具使用详解 – 3.3 为 Android App Bundle 生成 APK 集合
在生产的apk集合中(.apks文件),splits/
目录下存放着各种apk文件,其中base-master.apk
是基础apk,如果使用压缩工具打开,可以发现内部没有任何资产资源包的资源文件。资产资源包,在 asset-slices/
目录下的apk文件,每一个资源包对应一个apk文件。
- 将生成的apk集合安装到设备,如下示例:
bundletool install-apks --apks=demo-en-local-test.apks --device-id=28d612e
命令执行效果:
E:\RastarGameSDK\RastarGameSdkOverseaX\demo\en\release>java -jar D:\Android\bundletool\bundletool-all-1.7.1.jar install-apks --apks=demo-en-local-test.apks --device-id=28d612e
The APKs have been extracted in the directory: C:\Users\ADMINI~1.P-2\AppData\Local\Temp\5384271713776026715
The APKs have been extracted in the directory: C:\Users\ADMINI~1.P-2\AppData\Local\Temp\5384271713776026715
ADB << rm -rf '/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing'
ADB >> OK
ADB << mkdir -p '/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing' && rmdir '/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing' && mkdir -p '/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing'
ADB >> OK
Pushed "/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing/base-xxhdpi.apk"
Pushed "/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing/base-master.apk"
Pushed "/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing/base-th.apk"
Pushed "/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing/base-vi.apk"
Pushed "/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing/base-id.apk"
Pushed "/sdcard/Android/data/com.rastargame.sdk.oversea.demo/files/local_testing/base-zh.apk"
说明:使用bundletool工具向指定设备安装apk集合,会根据设备选择指定的apk进行安装(并不是安装apk集合中的所有apk)。
- 运行程序,验证资源是否正常读取。
五、快速跟进分发(fast-follow)与按需分发(on-demand)详解
快速跟进分发与按需分发比较类似,只是资源包的下载时机不一样。在资产分发配置,跟安装时分发是一致的(详细的请参考本文的4.1~4.3章节),不一样的地方就是资源的访问方式不一样。快速跟进分发和按需分发,资源包都不会随着程序下载安装而下载,而是程序下载安装之后才下载。下面将详细讲解一下集成步骤。
5.1 集成 Play Asset Delivery 库
快速跟进分发和按需分发,需要通过Play Asset Delivery 库来管理以及下载资源包。在程序级别的 build.gradle
文件的依赖声明处,添加以下依赖:
dependencies {
// This dependency is downloaded from the Google’s Maven repository.
// So, make sure you also include that repository in your project's build.gradle file.
implementation 'com.google.android.play:asset-delivery:2.1.0' // Java开发语言
// For Kotlin users also add the Kotlin extensions library for Play Asset Delivery:
implementation 'com.google.android.play:asset-delivery-ktx:2.1.0' // Kotlin开发语言
}
注意:以上两个依赖,跟进项目开发语言,选择其中一个即可。
5.2 Play Asset Delivery 库的使用
5.2.1 创建有效的AssetPackManager
对象
AssetPackManager
对象是所有API的入口,首先要创建一个有效的AssetPackManager
对象。如下示例:
// 有AssetPackManagerFactory工厂类创建一个AssetPackManager 实例对象
final AssetPackManager mAssetPackManager = AssetPackManagerFactory.getInstance(getApplicationContext());
5.2.1 查看资源包位置信息
每个资源包都存储在应用内部存储空间中的单独文件夹中,可以使用 getPackLocation()
方法确定资源包的根文件夹位置,此方法将会返回以下值:
返回值 | 状态 |
---|---|
null | 未知 Asset Pack 或资产无法使用 |
有效的 AssetPackLocation 对象 | 资源包根文件夹位于AssetPackLocation 对象 assetsPath() 指定的路径,现已可立即获取。 |
注意事项:应用应在每次启动时始终检查资源包是否有效(是否存在以及是否可用),请勿缓存资源包的路径信息,因为资源包可能会因应用更新或用户清除应用数据而变为无效。
5.2.2 获取资源包的状态信息
如果资源包无效(不可用),那么就需要获取资源包的状态信息,可以通过getPackStates()
(Java) 或 requestPackStates()
(Kotlin) 方法获取资源包的状态信息。状态信息包括资源包的大小、是否已下载(或者下载中的状态)等(Google也要求应用在提取资源包之前,必须向用户披露下载内容的大小)。本文基于 Java 开发语言,因此主要介绍 getPackStates()
方法的使用。getPackStates()
方法返回一个 Task<AssetPackStates>
的异步方法,AssetPackStates
对象的 packStates()
方法会返回一个映射表 Map<String, AssetPackState>
,此映射包含所请求的每个资源包的状态,按资源包名称进行键控。如下示例
final String assetPackName = "asset_res_pack"; // 资源包名称
mAssetPackManager.getPackStates(Arrays.asList(assetPackName))
.addOnCompleteListener(new OnCompleteListener<AssetPackStates>() {
@Override
public void onComplete(@NonNull Task<AssetPackStates> task) {
try {
LogUtils.e("Get asset pack states onComplete");
AssetPackStates assetPackStates = task.getResult();
AssetPackState assetPackState = assetPackStates.packStates().get(assetPackName);
if(null == assetPackState) {
LogUtils.e("No asset pack named '" + assetPackName + "'");
return;
}
LogUtils.e(String.format("Asset Pack(%s) status = %d\n%s\n%s\n%s", assetPackState.name()
,assetPackState.status()
," - totalBytesToDownload = " + assetPackState.totalBytesToDownload()
," - bytesDownloaded = " + assetPackState.bytesDownloaded()
," - transferProgressPercentage = " + assetPackState.transferProgressPercentage()));
if(AssetPackStatus.COMPLETED == assetPackState.status()) {
// 资源包已经下载并且转移,应用可以使用
LogUtils.e("Asset pack downloaded and transfer");
} else if(AssetPackStatus.NOT_INSTALLED == assetPackState.status()) {
// 资源包未安装
LogUtils.e("Asset pack not installed"); }
} catch (Exception e) {
LogUtils.e("Get asset pack onException -- " + e.getMessage());
}
}
});
程序安装后运行,执行以上代码进行检查,会得到以下输出:
从上面的示例可以看出,程序安装运行之后,资源包的状态是(NOT_INSTALLED = 8),从需要下载文件大小以及已经下载文件大小可以得出,这个状态是还未下载安装的。于是,接下来,就需要下载安装资源包数据。
5.2.3 下载安装资源包
下载和安装资源包,调用 fetch()
方法(Kotlin语言调用 requestFetch()
方法),该方法返回一个 Task<AssetPackStates>
类型的异步方法,如下示例:
mAssetPackManager.fetch(Arrays.asList(assetPackName));
注意:虽然
fetch()
方法返回的是一个Task<AssetPackStates>
类型的异步方法,但是该方法执行完成并不意味着资源包下载完成,可以使用addOnCompleteListener()
添加完成监听,方法执行完成之后, 资源包的状态是AssetPackStatus.PENDING = 1
,这个状态的含义是:资源包下载任务处于待办并将要处理(The asset pack download is pending and will be processed soon.)。
5.2.4 添加资源包状态监听
既然 fetch()
方法执行完成并不是资源包下载安装完成,那么我们需要有一个可以监测资源包状态变化的监听,这样才能掌握资源包的下载安装的过程以及何时完成,提供更加友好的UI交互,以及资源包现在安装完成之后进行下一步操作。添加资源包状态监听,在 AssetPackManager
实例对象中添加。如下示例:
final AssetPackStateUpdateListener mAssetPackStateUpdateListener = new AssetPackStateUpdateListener() {
@Override
public void onStateUpdate(@NonNull AssetPackState assetPackState) {
switch (assetPackState.status()) {
case AssetPackStatus.CANCELED:
LogUtils.e(String.format("Asset Pack(%s) status CANCELED", assetPackState.name()));
break;
case AssetPackStatus.COMPLETED:
LogUtils.e(String.format("Asset Pack(%s) status COMPLETED\n%s\n%s\n%s", assetPackState.name()
," - totalBytesToDownload = " + assetPackState.totalBytesToDownload()
," - bytesDownloaded = " + assetPackState.bytesDownloaded()
," - transferProgressPercentage = " + assetPackState.transferProgressPercentage()));
checkAssetPackStatus();
break;
case AssetPackStatus.DOWNLOADING:
LogUtils.e(String.format("Asset Pack(%s) status DOWNLOADING\n%s\n%s", assetPackState.name()
," - totalBytesToDownload = " + assetPackState.totalBytesToDownload()
," - bytesDownloaded = " + assetPackState.bytesDownloaded()));
break;
case AssetPackStatus.FAILED:
LogUtils.e(String.format("Asset Pack(%s) status FAILED", assetPackState.name()));
break;
case AssetPackStatus.NOT_INSTALLED:
LogUtils.e(String.format("Asset Pack(%s) status NOT_INSTALLED", assetPackState.name()));
break;
case AssetPackStatus.PENDING:
LogUtils.e(String.format("Asset Pack(%s) status PENDING", assetPackState.name()));
break;
case AssetPackStatus.TRANSFERRING:
LogUtils.e(String.format("Asset Pack(%s) status TRANSFERRING\n%s", assetPackState.name()
," - transferProgressPercentage = " + assetPackState.transferProgressPercentage()));
break;
case AssetPackStatus.UNKNOWN:
LogUtils.e(String.format("Asset Pack(%s) status UNKNOWN", assetPackState.name()));
break;
case AssetPackStatus.WAITING_FOR_WIFI:
LogUtils.e(String.format("Asset Pack(%s) status WAITING_FOR_WIFI", assetPackState.name()));
break;
default:
break;
}
}
};
// 注册监听
mAssetPackManager.registerListener(mAssetPackStateUpdateListener);
// 反注册监听,不在需要时,及时反注册监听,防止内存溢出
mAssetPackManager.unregisterListener(mAssetPackStateUpdateListener);
添加资源包状态监听之后,调用 fetch()
方法,将会得的如下的日志信息,可看到资源包下载安装成功的状态依次是 PENDING
-> DOWNLOADING
-> TRANSFERRING
-> COMPLETED
。其中 DOWNLOADING
和 TRANSFERRING
会根据资源文件的大小,可能会存在多次回调。下载安装资源包完成之后,再次调用获取资源包位置的方法,就可以成功获取到资源包的位置,获取资源包的资源并使用。
注意:在用户安装或更新应用后,Play 商店会自动触发下载所有快速跟进分发(fast-follow)的资源包。但是,当用户打开程序时,这些资源包可能还无法供用户使用(为完成下载安装)。因此,开发者必须在每次应用启动时检查快速跟进分发(fast-follow)的资源包的状态。如果正在下载,请使用监听器对其状态进行监控。如果下载已取消或暂停,可以使用
fetch()
方法恢复下载.。
5.2.5 内容较大的资源文件处理
Play Asset Delivery 库在下载内容较大(超过150MB)的资源文件时,如果用户没有明确同意使用移动数据下载,且没有连接Wi-Fi或者Wi-Fi连接断开,下载都将会暂停,资源包状态会变为 AssetPackStatus.WAITING_FOR_WIFI
。在此状态下,开发者可以使用 showCellularDataConfirmation()
方法(Kotlin语言环境使用 requestCellularDataConfirmation()
方法)弹出提示框,询问用户是否同意使用移动数据下载所有资源包,统一才会在一栋数据继续下载。 showCellularDataConfirmation()
方法返回一个 Task<Integer>
异步方法,可以通过 addOnSuccessListener()
添加监听获取用户操作结果,其中 Integer
类型数据为结果吗(ResultCcode),Activity.RESULT_OK
为用户同意,Activity.RESULT_CANCEL
为用户拒绝。如下示例:
boolean waitForWifiConfirmationShown = false;
final AssetPackStateUpdateListener mAssetPackStateUpdateListener = new AssetPackStateUpdateListener() {
@Override
public void onStateUpdate(@NonNull AssetPackState assetPackState) {
switch (assetPackState.status()) {
case AssetPackStatus.CANCELED:
LogUtils.e(String.format("Asset Pack(%s) status CANCELED", assetPackState.name()));
break;
case AssetPackStatus.COMPLETED:
LogUtils.e(String.format("Asset Pack(%s) status COMPLETED\n%s\n%s\n%s", assetPackState.name()
," - totalBytesToDownload = " + assetPackState.totalBytesToDownload()
," - bytesDownloaded = " + assetPackState.bytesDownloaded()
," - transferProgressPercentage = " + assetPackState.transferProgressPercentage()));
checkAssetPackStatus();
break;
case AssetPackStatus.DOWNLOADING:
LogUtils.e(String.format("Asset Pack(%s) status DOWNLOADING\n%s\n%s", assetPackState.name()
," - totalBytesToDownload = " + assetPackState.totalBytesToDownload()
," - bytesDownloaded = " + assetPackState.bytesDownloaded()));
break;
case AssetPackStatus.FAILED:
LogUtils.e(String.format("Asset Pack(%s) status FAILED", assetPackState.name()));
break;
case AssetPackStatus.NOT_INSTALLED:
LogUtils.e(String.format("Asset Pack(%s) status NOT_INSTALLED", assetPackState.name()));
break;
case AssetPackStatus.PENDING:
LogUtils.e(String.format("Asset Pack(%s) status PENDING", assetPackState.name()));
break;
case AssetPackStatus.TRANSFERRING:
LogUtils.e(String.format("Asset Pack(%s) status TRANSFERRING\n%s", assetPackState.name()
," - transferProgressPercentage = " + assetPackState.transferProgressPercentage()));
break;
case AssetPackStatus.UNKNOWN:
LogUtils.e(String.format("Asset Pack(%s) status UNKNOWN", assetPackState.name()));
break;
case AssetPackStatus.WAITING_FOR_WIFI:
LogUtils.e(String.format("Asset Pack(%s) status WAITING_FOR_WIFI", assetPackState.name()));
if(!waitForWifiConfirmationShown) {
mAssetPackManager.showCellularDataConfirmation(RSDemoActivity.this)
.addOnSuccessListener(new OnSuccessListener<Integer>() {
@Override
public void onSuccess(Integer resultCode) {
if(RESULT_OK == resultCode) {
LogUtils.e("showCellularDataConfirmation --- User agree");
} else if(RESULT_CANCELED == resultCode) {
LogUtils.e("showCellularDataConfirmation --- User denied");
}
}
});
waitForWifiConfirmationShown = true;
}
break;
default:
break;
}
}
};
注意:如果应用不在
AssetPackStatus.WAITING_FOR_WIFI
状态下调用此方法询问用户,默认只能在 Wi-Fi 网络下载,因此资源包下载将会暂停,仅当用户连接到 Wi-Fi 网络环境时才会自动恢复下载。
5.2.6 资源包资源的获取
当某个资源包的状态变为 AssetPackStatus.COMPLETED
,即已经完成下载并安装,此时就可以使用 getPackLocation()
方法获取资源包的位置(参考:5.2.2 获取资源包的状态信息),assetsPath()
方法获取的路径及资源包安装的 assets
路径(示例:/data/data/com.rastargame.sdk.oversea.demo/files/assetpacks/asset_res_pack/210/210/assets
),该目录下的文件结构,跟创建资源包时的目录结构一致。接下来,程序就可以通过文件读写的 API 访问资源包内容。
说明:资源包下载安装至应用内部数据目录,因此访问文件不需要存储权限。
5.3 Play Asset Delivery 库的其他方法
5.3.1 取消请求资源包
使用 cancel()
方法可以取消资源包的请求操作。
注意:取消请求操作,是尽力而为的操作,并不一定会达到预期的效果。
5.3.2 移除资源包
使用 removePack()
(Kotlin语言环境为 requestRemovePack()
)方法,可以移除资源包。
5.3.3 获取多个资源包的位置信息
使用 getPackLocations()
可以批量查询多个资源包的状态,此方法将返回资源包与其位置的映射。getPackLocations()
返回的映射包含当前已下载且为最新状态的每个资源包的条目。
5.4 本地测试
快速根据分发本地测试跟安装时分发步骤基本一致,可以参考:4.5 本地测试
注意:由于快速跟进分发和按需分发的资源包,需要在应用安装后进行下载,本地测试只能模拟下载过程,并不是真实的从网络环境下载,在应用安装时就将资源包存储在设备存储中,因此对于快速跟进分发和按需分发的本地测试,无法测试网络
WAITING_FOR_WIFI
的场景。另外,本地测试也不支持更新,需要手动卸载旧版本。
六、编后语
对于 Google Play 的资产分发,可以有效解决 apk 大小限制,巧用快速跟进分发和按需分发,也可以提高用户体验。对 Google Play 的资产分发就介绍到这,喜欢的朋友就点个赞吧。