Android 打包AAB+PAD(Unity篇)

2021/08 30 18:08

AAB

Android App Bundle 是 Android 新推出的一种官方发布格式,可让你以更高效的方式开发和发布应用。借助 Android App Bundle,你可以更轻松地以更小的应用提供优质的使用体验,从而提升安装成功率并减少卸载量。转换过程轻松便捷。你无需重构代码即可开始获享较小应用的优势。改用这种格式后,你可以体验模块化应用开发和可自定义功能交付,并从中受益。

Play Asset Delivery

Play Asset Delivery (PAD) 将 app bundle 的优势带到游戏中。它允许超过 150 MB 的游戏替换旧版扩展文件 (OBB),方法是将包含游戏所需的所有资源的单个工件发布到 Play。PAD 提供了灵活的分发模式、自动更新、压缩和增量修补功能,并且可免费使用。使用 PAD,所有资源包均在 Google Play 上托管和提供,因此你无需使用内容分发网络 (CDN) 向玩家提供游戏资源。

Play Asset Delivery 使用资源包,资源包由资源(如纹理、着色器和声音)组成,但不包含可执行代码。通过 Dynamic Delivery,你可以按照以下三种分发模式自定义如何以及何时将各个资源包下载到设备上:「安装时分发」「快速跟进式分发」「按需分发」

分发模式

「install-time」 资源包在用户安装应用时分发。这些资源包以拆分 APK(APK 集的一部分)的形式提供。它们也称为“预先”资源包;您可以在应用启动时立即使用这些资源包。这些资源包会增加 Google Play 商店上列出的应用大小。用户无法修改或删除这些资源包。

「fast-follow」 资源包会在用户安装应用后立即自动下载;用户无需打开应用即可开始 fast-follow 下载。此类下载不会阻止用户访问应用。这些资源包会增加 Google Play 商店上列出的应用大小。

「on-demand」 资源包会在应用运行时下载。

Google Play 商店会以归档文件(而非拆分 APK)的形式提供配置为 fast-follow 和 on-demand 的资源包。这些资源包随后会在应用的内部存储空间中展开。您可以使用 Play Core API 查询以这种方式提供的资源包的位置。应用无法假设这些文件的存在或其位置,因为它们可能会被用户删除,或由 Play Core SDK 在游戏会话之间移动。尽管这些文件可由应用写入,您也应将其视为只读文件,因为资源包补丁程序依赖于这些文件的完整性。

资源更新

更新应用时,「install-time」 Asset Pack 会作为基础应用更新的一部分进行更新(开发者无需执行任何操作)。

对于 「fast-follow」 和 「on-demand」 Asset Pack 的应用更新,则遵循以下步骤:

  • 1、系统将应用的补丁程序(包括所有资产)下载到设备上的安全位置。
  • 2、更新应用二进制文件;这包括所有 install-time Asset Pack。
  • 3、之前下载的所有 Asset Pack 变为无效。
  • 4、将资产的补丁程序复制并应用到存储在应用内部存储空间中的资产。

在大多数情况下,当用户打开游戏时,整体更新已完成,用户可以立即开始玩更新后的版本。在极少数情况下,当用户打开应用时,应用二进制文件可能已完成更新,但资产的补丁程序应用过程尚未完成,因此用户尚无法访问这些资产。为了应对此类情形,您需要针对这些资产提供相应的“正在更新”界面元素,或构建逻辑来处理尚无法访问的无效资源。由于只有在所有 Asset Pack 类型均已下载后,应用二进制文件才会更新,因此补丁程序的应用操作会在本地以离线方式进行,且应快速完成。

纹理压缩格式定位

纹理压缩是一种有损图像压缩,可让 GPU 使用专用硬件直接从压缩纹理进行渲染,从而减少所需的纹理内存和内存带宽用量。借助纹理压缩格式定位功能,您可以在 Android App Bundle 中添加使用多种纹理压缩格式压缩的纹理,并且依靠 Google Play 自动为每种设备提供采用最佳纹理压缩格式的资源。

应用版本更新

新版本的应用上传到 Google Play 后,如果用户未在设备上更新该应用,他们可以打开之前的应用版本。在这种情况下,如有必要,应用可以通过调用 In-App Updates API 选择强制更新或建议更新。借助此 API,您可以从应用内触发更新,而不是让用户从 Google Play 商店触发更新。

下载大小上限

Asset Pack 因具有较高的大小上限而成为大型游戏的理想之选:

  • 1、每个 fast-follow 和 on-demand Asset Pack 的下载大小上限为 512 MB。
  • 2、所有 install-time Asset Pack 的总下载大小上限为 1 GB。
  • 3、一个 Android App Bundle 中的所有 Asset Pack 的总下载大小上限为 2 GB。
  • 4、一个 Android App Bundle 中最多可以使用 50 个资源包。

如果你使用的是纹理压缩格式定位,那么这些下载限制会分别应用于每个独一无二的纹理格式。

针对 Unity 构建

Unity AssetBundle 文件包含可在应用程序运行时由 Unity 引擎加载的序列化资产。这些文件是特定于平台的(例如,为 Android 构建)并且可以与资产包结合使用。最常见的是, 「一个 AssetBundle 文件被打包成一个资产包」,该包使用与 AssetBundle 相同的名称。

  • 1、获取 Play Asset Delivery 的 Unity 插件(或包)。

「注意:」 Google Play 核心库的下载和使用受Play 核心软件开发工具包服务条款的约束。下载和使用 Google Play 核心库,「即表示你同意 Play 核心软件开发工具包服务条款」

Unity 插件可用于精选的 Play 核心 API,包括 Play Asset Delivery。从Google Play Plugins for Unity 版本下载最新版本。这是一个包含 Play Core 插件以及其他 Play 插件(例如 Play In-app Billing 和 Play Instant)的单一软件包。

「注意:」 你可以使用 Unity AssetBundle Browser 在你的 Unity 项目中创建和管理 AssetBundle。

使用 UI 配置 AssetBundles

  • 1、在资产包中配置每个 AssetBundle:
    • 选择Google > Android App Bundle > Asset Delivery设置。
    • 要选择直接包含 AssetBundle 文件的文件夹,请单击添加文件夹。
  • 2、对于每个捆绑包,将Asset Delivery更改为「Install Time」「Fast Follow」「On Demand」。解决任何错误或依赖项并关闭窗口。
  • 3、选择Google > Build Android App Bundle以构建应用程序包。
  • 4、(可选)配置你的应用程序包以支持不同的纹理压缩格式。

常见的纹理压缩格式:

  • DDS 或 S3TC:有时称为 DXTC 或 DXTn。OpenGL 支持此格式的三种形式。
  • ETC1:大多数设备都支持此格式。这种格式不支持透明度,但游戏可将第二个纹理文件用于 Alpha 通道组件。
  • ETC2:支持 GLES3 的所有设备均支持此格式。
  • PVRTC:iOS 游戏常用的格式,在某些 Android 设备上也受支持。
  • ASTC:专为取代之前的格式而设计的新格式。比先前的格式更加灵活,因为它支持各种块大小。使用这种格式可以帮助您优化游戏大小。

支持的格式及支持相应格式设备所占的百分比:

使用 API 配置资产包

你可以通过编辑器脚本配置资产交付,这些脚本可以作为自动构建系统的一部分运行。

使用 AssetPackConfig 该类来定义要包含在 Android App Bundle 构建中的资产,以及模式。这些资产包不需要包含 AssetBundle。

public void ConfigureAssetPacks {   // Creates an AssetPackConfig with a single asset pack, named   // examplePackName, containing all the files in path/to/exampleFolder.   var assetPackConfig = new AssetPackConfig();   assetPackConfig.AddAssetsFolder("examplePackName",                                   "path/to/exampleFolder",                                   AssetPackDeliveryMode.OnDemand);   // Configures the build system to use the newly created assetPackConfig when   // calling Google > Build and Run or Google > Build Android App Bundle.   AssetPackConfigSerializer.SaveConfig(assetPackConfig);   // Alternatively, use BundleTool.BuildBundle to build an App Bundle from script.   BuildBundle(new buildPlayerOptions(), assetPackConfig);}

你还可以使用类中的静态 BuildBundle 方法Bundletool生成带有资产包的 Android App Bundle,给定 「BuildPlayerOptions」 和 「AssetPackConfig」

Play Asset Delivery Unity API 集成

该 「Play Asset Delivery Unity API」 提供了请求资产包,下载管理,和访问资源的功能。「确保」首先将 Unity 插件添加到你的项目中。

你在 API 中使用的函数取决于你创建资产包的方式。

  • 如果你使用 UI 配置 AssetBundles,请「选择插件配置的资产包」
  • 如果你使用 API 配置资产包,请选「择API 配置的资产包」

你可以根据要访问的资产包的交付类型实施 API。这些步骤显示在以下流程图中。

检索 AssetBundles

导入 Play Asset Delivery API 并调用该 RetrieveAssetBundleAsync()方法来检索 AssetBundle。

using Google.Play.AssetDelivery;// Loads the AssetBundle from disk, downloading the asset pack containing it if necessary.PlayAssetBundleRequest bundleRequest = PlayAssetDelivery.RetrieveAssetBundleAsync(asset-bundle-name);

安装时交货

资产包配置为「install-time」在应用程序启动时立即可用。你可以使用以下命令从 AssetBundle 加载场景:

AssetBundle assetBundle = bundleRequest.AssetBundle;// You may choose to load scenes from the AssetBundle. For example:string[] scenePaths = assetBundle.GetAllScenePaths();SceneManager.LoadScene(scenePaths[path-index]);

快速跟进和按需交付

这些部分适用于「fast-follow」「on-demand」资产包。

检查状态

每个资产包都存储在应用程序内部存储的单独文件夹中。使用该 「isDownloaded()」 方法确定是否已下载资产包。

监控下载

查询PlayAssetBundleRequest 监控请求状态的 对象:

// Download progress of request, between 0.0f and 1.0f. The value will always be// 1.0 for assets delivered as install-time.// NOTE: A value of 1.0 will only signify the download is complete. It will still need to be loaded.float progress = bundleRequest.DownloadProgress;// Returns true if://   * it had either completed the download, installing, and loading of the AssetBundle,//   * OR if it has encountered an error.bool done = bundleRequest.IsDone;// Returns status of retrieval request.AssetDeliveryStatus status = bundleRequest.Status;switch(status) {    case AssetDeliveryStatus.Pending:        // Asset pack download is pending - N/A for install-time assets.    case AssetDeliveryStatus.Retrieving:        // Asset pack is being downloaded and transferred to app storage.        // N/A for install-time assets.    case AssetDeliveryStatus.Available:        // Asset pack is downloaded on disk but NOT loaded into memory.        // For PlayAssetPackRequest(), this indicates that the request is complete.    case AssetDeliveryStatus.Loading:        // Asset pack is being loaded.    case AssetDeliveryStatus.Loaded:        // Asset pack has finished loading, assets can now be loaded.        // For PlayAssetBundleRequest(), this indicates that the request is complete.    case AssetDeliveryStatus.Failed:        // Asset pack retrieval has failed.    case AssetDeliveryStatus.WaitingForWifi:        // Asset pack retrieval paused until either the device connects via Wi-Fi,        // or the user accepts the PlayAssetDelivery.ShowCellularDataConfirmation dialog.    default:        break;}

大量下载

大于 150MB 的资产包可以自动下载,但只能通过 Wi-Fi 下载。如果用户未连接到 Wi-Fi,则PlayAssetBundleRequest状态设置为 AssetDeliveryStatus.WaitingForWifi 并暂停下载。在这种情况下,要么等待设备连接到 Wi-Fi,然后继续下载,要么提示用户批准通过蜂窝连接下载包。

if(bundleRequest.Status == AssetDeliveryStatus.WaitingForWifi) {    var userConfirmationOperation = PlayAssetDelivery.ShowCellularDataConfirmation();    yield return userConfirmationOperation;    switch(userConfirmationOperation.GetResult()) {        case ConfirmationDialogResult.Unknown:            // userConfirmationOperation finished with an error. Something went            // wrong when displaying the prompt to the user, and they weren't            // able to interact with the dialog. In this case, we recommend            // developers wait for Wi-Fi before attempting to download again.            // You can get more info by calling GetError() on the operation.        case ConfirmationDialogResult.Accepted:            // User accepted the confirmation dialog - download will start            // automatically (no action needed).        case ConfirmationDialogResult.Declined:            // User canceled or declined the dialog. Await Wi-Fi connection, or            // re-prompt the user.        default:            break;    }}

取消请求(仅限按需)

如果需要在 AssetBundles 加载到内存之前取消请求,请调用 对象AttemptCancel() 上的方法 PlayAssetBundleRequest:

// Will only attempt if the status is Pending, Retrieving, or Available - otherwise// it will be a no-op.bundleRequest.AttemptCancel();// Check to see if the request was successful by checking if the error code is Canceled.if(bundleRequest.Error == AssetDeliveryErrorCode.Canceled) {    // Request was successfully canceled.}

异步请求资产包

在大多数情况下,你应该使用 Coroutines异步请求资产包并监控进度,如下所示:

private IEnumerator LoadAssetBundleCoroutine(string assetBundleName) {    PlayAssetBundleRequest bundleRequest =        PlayAssetDelivery.RetrieveAssetBundleAsync(assetBundleName);    while (!bundleRequest.IsDone) {        if(bundleRequest.Status == AssetDeliveryStatus.WaitingForWifi) {            var userConfirmationOperation = PlayAssetDelivery.ShowCellularDataConfirmation();            // Wait for confirmation dialog action.            yield return userConfirmationOperation;            if((userConfirmationOperation.Error != AssetDeliveryErrorCode.NoError) ||               (userConfirmationOperation.GetResult() != ConfirmationDialogResult.Accepted)) {                // The user did not accept the confirmation - handle as needed.            }            // Wait for Wi-Fi connection OR confirmation dialog acceptance before moving on.            yield return new WaitUntil(() => bundleRequest.Status != AssetDeliveryStatus.WaitingForWifi);        }        // Use bundleRequest.DownloadProgress to track download progress.        // Use bundleRequest.Status to track the status of request.        yield return null;    }    if (bundleRequest.Error != AssetDeliveryErrorCode.NoError) {        // There was an error retrieving the bundle. For error codes NetworkError        // and InsufficientStorage, you may prompt the user to check their        // connection settings or check their storage space, respectively, then        // try again.        yield return null;    }    // Request was successful. Retrieve AssetBundle from request.AssetBundle.    AssetBundle assetBundle = bundleRequest.AssetBundle;

其他 Play Core API 方法

以下是你可能希望在应用中使用的一些其他 API 方法。

检查下载大小

通过对 Google Play 进行异步调用并设置操作完成时的回调方法来检查 AssetBundle 的大小:

public IEnumerator GetDownloadSize() {   PlayAsyncOperation<long> getSizeOperation =   PlayAssetDelivery.GetDownloadSize(assetPackName);   yield return getSizeOperation;   if(operation.Error != AssetDeliveryErrorCode.NoError) {       // Error while retrieving download size.    } else {        // Download size is given in bytes.        long downloadSize = operation.GetResult();    }}

移除 AssetBundles

你可以删除当前未加载到内存中的快速关注和按需 AssetBundle。进行以下异步调用并设置完成时的回调方法:

PlayAsyncOperation<string> removeOperation = PlayAssetDelivery.RemoveAssetPack(assetBundleName);removeOperation.Completed += (operation) =>            {                if(operation.Error != AssetDeliveryErrorCode.NoError) {                    // Error while attempting to remove AssetBundles.                } else {                    // Files were deleted OR files did not exist to begin with.                }            };

测试

在 Unity Editor 中,选择Google > Build and Run。

行为

「install-time」 包将在应用程序安装过程中安装。

「fast-follow」包的行为与「on-demand」包一样。也就是说,当游戏被侧载时它们不会被自动获取。开发者需要在游戏开始时手动请求;这不需要你的应用程序中的任何代码更改。

限制

以下是本地测试的限制:

  • Packs 从外部存储而不是 Play 中获取,因此您无法测试您的代码在出现网络错误的情况下的行为。
  • 本地测试不包括等待 Wi-Fi 场景。
  • 不支持更新。在安装新版本的构建之前,请手动卸载以前的版本。

使用内部应用共享进行测试

当你接近发布候选版本时,请使用尽可能真实的配置来测试你的游戏,以确保你的游戏在生产环境中为您的用户提供良好的性能。 构建您的应用程序包。

要使用内部应用程序共享测试资产交付,请执行以下操作:

  • 构建你的应用程序包。
  • 按照 Play 管理中心的说明进行操作,了解如何在 内部共享您的应用。
  • 在测试设备上,单击您刚刚上传的应用程序版本的内部应用程序共享链接。
  • 从点击链接后看到的 Google Play 商店页面安装应用程序。

转自:https://mdnice.com/writing/e9a2385c7d714e53b0621b976e112d3f