集成资源交付 (Unity)

在集成资源交付时,Unity 游戏可以使用 Addressables 或 AssetBundles 访问资源包。对于使用 Unity 2019.4 或更高版本构建的游戏,Addressables 是更新且推荐的资源交付解决方案,而 AssetBundles 则在 Unity 2017.4 和 2018.4 中提供资源包支持。

Unity Addressables

使用 Unity 2019.4 或更高版本构建的游戏应使用 Addressables 在 Android 上进行资源交付。Unity 提供了一个 Play Asset Delivery (PAD) API,用于使用 Addressables 处理 Android 资源包。有关使用 Addressables 的信息,请参阅以下内容:

使用 AssetBundle 文件

使用 Unity 2017.4 和 2018.4 构建的游戏可以使用 AssetBundle 文件在 Android 上进行资源交付。Unity AssetBundle 文件包含序列化资产,Unity 引擎可以在应用运行时加载这些资产。这些文件是平台特定的(例如,为 Android 构建),可以与资源包结合使用。最常见的情况是,一个 AssetBundle 文件被打包到一个资源包中,该资源包使用与 AssetBundle 相同的名称。如果您希望在创建资源包时具有更大的灵活性,请使用 API 配置资源包。

在运行时,使用 Play Asset Delivery for Unity 类检索打包在资源包中的 AssetBundle。

先决条件

  1. 设置您的开发环境

OpenUPM-CLI

如果您安装了 OpenUPM CLI,您可以使用以下命令安装 OpenUPM 注册表

openupm add com.google.play.assetdelivery

OpenUPM

  1. 选择 Unity 菜单选项 Edit > Project Settings > Package Manager,打开包管理器设置

  2. 将 OpenUPM 添加为包管理器窗口的限定范围注册表

    Name: package.openupm.com
    URL: https://package.openupm.com
    Scopes: com.google.external-dependency-manager
      com.google.play.common
      com.google.play.core
      com.google.play.assetdelivery
      com.google.android.appbundle
    
  3. 选择 Unity 菜单选项 Window > Package Manager,打开包管理器菜单

  4. 将管理器范围下拉菜单设置为 My Registries

  5. 从包列表中选择 Google Play Integrity plugin for Unity 包,然后按 Install

从 GitHub 导入

  1. 从 GitHub 下载最新的 .unitypackage 版本。

  2. 选择 Unity 菜单选项 Assets > Import package > Custom Package 并导入所有项目,以导入 .unitypackage 文件。

  1. 在 Unity 中创建 AssetBundles.

使用 UI 配置 AssetBundles

  1. 配置资源包中的每个 AssetBundle

    1. 选择 Google > Android App Bundle > Asset Delivery Settings
    2. 要选择直接包含 AssetBundle 文件的文件夹,请点击 Add Folder

  2. 对于每个 bundle,将 Delivery Mode 更改为 Install TimeFast FollowOn Demand。解决任何错误或依赖项并关闭窗口。

  3. 选择 Google > Build Android App Bundle 以构建应用 bundle。

  4. (可选)配置您的应用 bundle 以支持不同的纹理压缩格式

使用 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);
}

您还可以使用 Bundletool 类中的静态 BuildBundle 方法,根据 BuildPlayerOptionsAssetPackConfig 生成一个带资源包的 Android App Bundle。

有关引导式教程,请参阅 在 Unity 游戏中使用 Play Asset Delivery Codelab

与 Play Asset Delivery Unity API 集成

Play Asset Delivery Unity API 提供了请求资源包、管理下载和访问资产的功能。请务必先将Unity 插件添加到您的项目。

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

如果您使用插件 UI 创建了资源包,请选择 Plugin-configured asset packs

如果您使用 API(或插件 UI)创建了资源包,请选择 API-configured asset packs

您根据要访问的资源包的交付类型来实现 API。以下流程图显示了这些步骤。

Asset pack flow diagram for the plugin

图 1. 访问资源包的流程图

检索 AssetBundles

导入 Play Asset Delivery 库并调用 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-followon-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.ShowConfirmationDialog dialog.
    case AssetDeliveryStatus.RequiresUserConfirmation:
        // Asset pack retrieval paused until the user accepts the
        // PlayAssetDelivery.ShowConfirmationDialog dialog.
    default:
        break;
}

大型下载

大于 200MB 的资源包可以自动下载,但仅限于 Wi-Fi。如果用户没有连接到 Wi-Fi,PlayAssetBundleRequest 状态将设置为 AssetDeliveryStatus.WaitingForWifi,并且下载会暂停。在这种情况下,可以等待设备连接到 Wi-Fi,然后继续下载,或者提示用户批准通过蜂窝连接下载资源包。

需要用户确认

如果一个资源包的状态为 AssetDeliveryStatus.RequiresUserConfirmation,则在用户接受通过 PlayAssetDelivery.ShowConfirmationDialog() 显示的对话框之前,下载不会进行。如果应用未被 Play 识别,可能会出现此状态。请注意,在这种情况下调用 PlayAssetDelivery.ShowConfirmationDialog() 会导致应用更新。更新后,请再次请求资产。

if(request.Status == AssetDeliveryStatus.RequiresUserConfirmation
   || request.Status == AssetDeliveryStatus.WaitingForWifi) {
    var userConfirmationOperation = PlayAssetDelivery.ShowConfirmationDialog();
    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.
        case ConfirmationDialogResult.Accepted:
            // User accepted the confirmation dialog--an update will start.
        case ConfirmationDialogResult.Declined:
            // User canceled or declined the dialog. It can be shown again.
        default:
            break;
    }
}

取消请求(仅限按需)

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

// 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.
}

异步请求资源包

在大多数情况下,您应该使用 协程来异步请求资源包并监控进度,如下所示:

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;

有关错误处理的更多信息,请参阅 AssetDeliveryErrorCodes 列表。

其他 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

您可以移除当前未加载到内存中的快速跟踪和按需 AssetBundles。进行以下异步调用并设置其完成时的回调方法

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.
                }
            };

后续步骤

在本地和从 Google Play 测试资源交付