在集成资源交付时,Unity 游戏可以使用 Addressables 或 AssetBundles 访问资源包。Addressables 是 Unity 2019.4 或更高版本构建的游戏中更新且推荐的资源交付解决方案,而 AssetBundles 在 Unity 2017.4 和 2018.4 中提供对资源包的支持。
Unity Addressables
使用 Unity 2019.4 或更高版本构建的游戏应使用 Addressables 在 Android 上进行资源交付。Unity 提供了一个 Play Asset Delivery (PAD) API,用于使用 Addressables 处理 Android 资源包。有关使用 Addressables 的信息,请参阅以下内容
- Android 包的 Addressables
- Unity 的 PAD 指南
- Unity 的 PAD API 参考文档
使用 AssetBundle 文件
使用 Unity 2017.4 和 2018.4 构建的游戏可以在 Android 上使用 AssetBundle 文件进行资源交付。Unity AssetBundle 文件包含可由 Unity 引擎在应用运行时加载的序列化资源。这些文件是特定于平台的(例如,为 Android 构建),并且可以与资源包结合使用。最常见的是,一个 AssetBundle 文件被打包到一个资源包中,该包使用与 AssetBundle 相同的名称。如果您希望在创建资源包方面有更大的灵活性,请使用 API 配置资源包。
在运行时,使用 Unity 的 Play Asset Delivery 类检索打包在资源包中的 AssetBundle。
先决条件
从 Unity 的 Google 软件包 下载 Play Asset Delivery Unity 插件的最新版本。
使用 UI 配置 AssetBundles
在资源包中配置每个 AssetBundle
- 选择Google > Android 应用包 > 资源交付设置。
- 要选择直接包含 AssetBundle 文件的文件夹,请点击添加文件夹。
对于每个包,将交付模式更改为安装时、快速跟随或按需。解决任何错误或依赖项,然后关闭窗口。
选择Google > 构建 Android 应用包以构建应用包。
(可选)配置您的应用包以支持不同的 纹理压缩格式。
使用 API 配置资源包
您可以通过可以在自动化构建系统的一部分中运行的编辑器脚本配置资源交付。
使用 AssetPackConfig
类定义要包含在 Android 应用包构建中的资源以及资源的交付模式。这些资源包不需要包含 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
方法生成包含资源包的 Android 应用包,方法是提供 BuildPlayerOptions 和 AssetPackConfig
。
有关分步教程,请参阅 在 Unity 游戏中使用 Play Asset Delivery 的 Codelab。
与 Play Asset Delivery Unity API 集成
Play Asset Delivery Unity API 提供了请求资源包、管理下载和访问资源的功能。请确保先 将 Unity 插件添加到您的项目中。
您在 API 中使用的函数取决于您创建资源包的方式。
如果您 使用插件 UI 创建了资源包,请选择插件配置的资源包。
如果您 使用 API(或插件 UI)创建了资源包,请选择API 配置的资源包。
根据您希望访问的资源包的交付类型,实现 API。以下流程图显示了这些步骤。
检索 AssetBundle
导入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-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.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; } }
取消请求(仅限按需)
如果需要在 AssetBundle 加载到内存之前取消请求,请在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(); } }
删除 AssetBundle
您可以删除当前未加载到内存中的快速后续交付和按需 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. } };
后续步骤
在本地和 Google Play 上测试资源包交付。