整合資產提供功能 (Unity)

整合資產提供功能時,Unity 遊戲可以使用 Addressables 或 AssetBundle 存取資產包。Addressables 是最近建議使用的資產提供解決方案,適用於使用 Unity 2019.4 以上版本建構的遊戲,而 AssetBundle 則支援 Unity 2017.4 和 2018.4 中的資產包。

Unity Addressables

使用 Unity 2019.4 以上版本建構的遊戲應在 Android 上將 Addressables 用於提供資產。Unity 提供 Play Asset Delivery (PAD) API,以使用 Addressables 處理 Android 資產包。如要進瞭解如何使用 Addressables,請參閱下列資訊:

使用 AssetBundle 檔案

使用 Unity 2017.4 和 2018.4 建構的遊戲可以在 Android 上將 AssetBundle 檔案用於提供資產。Unity 的 AssetBundle 檔案具有序列化的資產,可在應用程式執行時由 Unity 引擎載入。這些檔案依平台而異 (例如 Android 專用),可與資產包共同使用。大多數情況下,一個 AssetBundle 檔案會封裝成單一的資產包,以及使用與 AssetBundle 相同名稱的套件。如果想更靈活地建立資產包,請使用 API 設定資產包。

在執行階段,使用 Unity 專屬 Play Asset Delivery 類別擷取封裝於資產包內的 AssetBundle。

必要條件

  1. Unity 的 Google 套件下載最新版 Play Asset Delivery Unity 外掛程式。

  2. 在 Unity 中建立 AssetBundle

透過 UI 設定 AssetBundle

  1. 設定資產包中的各項 AssetBundle:

    1. 選擇「Google」>「Android App Bundle」>「Asset Delivery 設定」
    2. 若要直接選取具有 AssetBundle 檔案的資料夾,請按一下「新增資料夾」

  2. 將每個套裝組合的「交付模式」變更為「安裝時間」、「快速追蹤」或「隨選」。解決任何錯誤或依附元件,接著關閉視窗。

  3. 選擇「Google」>「建立 Android App Bundle」建立應用程式套件。

  4. (選用)設定您的應用程式套件以支援不同的紋理壓縮格式

使用 API 設定資產包

您可以透過編輯器指令碼設定 Asset Delivery,該指令碼可以作為自動建構系統的一部分執行。

使用 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 方法來產生 Android App Bundle 以及資產包,前提是 BuildPlayerOptionsAssetPackConfig

如需輔助教學文件,請參閱在 Unity 遊戲程式碼研究室中使用 Play Asset Delivery 一文。

與 Play Asset Delivery Unity API 整合

Play Asset Delivery Unity API 提供的功能包括要求資產包、管理下載內容及存取資產等。請務必先新增 Unity 外掛程式至您的專案中。

您使用 API 的功能取決於您建立資產包的方式。

如果您使用外掛程式 UI 建立資產包,請選擇外掛程式設定的資產包

如果您使用 API(或外掛程式 UI)建立資產包,請選擇 API 設定的資產包

您可以根據想要存取的資產包的傳遞類型來實作 API。步驟請參見下方流程圖。

外掛程式的資產包流程圖

圖 1.存取資產包的流程圖

擷取 AssetBundle

匯入 Play Asset Delivery 程式庫並呼叫 RetrieveAssetBundleAsync() 方法,以擷取 Asset Bundle。

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.ShowCellularDataConfirmation dialog.
    default:
        break;
}

大型下載內容

大小超過 150 MB 的資產包只有在與 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;
    }
}

取消要求(僅限隨選)

若要在 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 中測試 Asset Delivery