整合資產提供功能時,Unity 遊戲可以使用 Addressable 或 AssetBundle 存取資產包。Addressable 是我們最近建議使用的資產提供解決方案,適用於使用 Unity 2019.4 以上版本建構的遊戲,而 AssetBundle 則支援 Unity 2017.4 和 2018.4 中的資產包。
Unity Addressable
若是使用 Unity 2019.4 以上版本建構的遊戲,應使用 Addressable 在 Android 上提供資產。Unity 提供 Play Asset Delivery (PAD) API,以便使用 Addressable 處理 Android 資產包。如要瞭解如何使用 Addressable,請參閱下列資源:
- Android 套件的 Addressable
- Unity 的 PAD 指南
- Unity 的 PAD API 參考說明文件
使用 AssetBundle 檔案
若是使用 Unity 2017.4 和 2018.4 建構的遊戲,可以使用 AssetBundle 檔案在 Android 上提供資產。Unity 的 AssetBundle 檔案具有序列化的資產,可在應用程式執行時由 Unity 引擎載入。這些檔案依平台而異 (例如專為 Android 建構的檔案),可與資產包搭配使用。大多數情況下,一個 AssetBundle 檔案會封裝成單一資產包,以及名稱與 AssetBundle 相同的套件。如果想更靈活地建立資產包,請使用 API 設定資產包。
請在執行階段,使用 Unity 專屬 Play Asset Delivery 類別擷取封裝於資產包內的 AssetBundle。
必要條件
- 設定開發環境:
OpenUPM-CLI
如果您已安裝 OpenUPM CLI,可以使用下列指令安裝 OpenUPM 登錄:
openupm add com.google.play.assetdelivery
OpenUPM
選取 Unity 選單選項「Edit」>「Project Settings」>「Package Manager」,開啟套件管理工具設定。
將 OpenUPM 新增為 Package Manager 視窗中的有範圍限制的登錄檔:
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
選取 Unity 選單選項「Window」>「Package Manager」,即可開啟「package manager」選單。
將管理員範圍下拉式選單設為「我的註冊中心」。
從套件清單中選取「Google Play Integrity 外掛程式 (適用於 Unity)」套件,然後按下「Install」。
從 GitHub 匯入
從 GitHub 下載最新的
.unitypackage
版本。選取 Unity 選單選項「Assets」>「Import package」>「Custom Package」,然後匯入所有項目,即可匯入
.unitypackage
檔案。
透過 UI 設定 AssetBundle
設定資產包中的各項 AssetBundle:
- 依序選取「Google」>「Android App Bundle」>「Asset Delivery Settings」。
- 若要直接選取含有 AssetBundle 檔案的資料夾,請按一下「Add Folder」。
將每個套件的「Delivery Mode」變更為「Install Time」、「Fast Follow」或「On Demand」。解決任何錯誤或依附元件,接著關閉視窗。
依序選取「Google」>「Build Android App 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
方法,產生內含資產包的 Android App Bundle,但前提是要有 BuildPlayerOptions 和 AssetPackConfig
。
如需輔助教學文件,請參閱在 Unity 遊戲程式碼研究室中使用 Play Asset Delivery 一文。
與 Play Asset Delivery Unity API 整合
Play Asset Delivery Unity API 提供的功能包括要求資產包、管理下載內容及存取資產等。請務必先將 Unity 外掛程式新增至專案。
您使用 API 的功能取決於您建立資產包的方式。
如果您使用外掛程式 UI 建立資產包,請選取「外掛程式設定的資產包」。
如果您使用 API (或外掛程式 UI) 建立資產包,請選取「API 設定的資產包」。
無論您想存取的資產包交付類型為何,其 API 是類似的。步驟請參見下方流程圖。
圖 1. 存取資產包的流程圖
擷取資產包
如要在磁碟中還沒有最新版資產包時下載資產包,請匯入 Play Asset Delivery 程式庫,並呼叫 RetrieveAssetPackAsync()
方法。
using Google.Play.AssetDelivery; // After download, the assets and/or AssetBundles contained in the asset pack // are not loaded into memory. PlayAssetPackRequest request = PlayAssetDelivery.RetrieveAssetPackAsync(assetPackName);
安裝時提供
設定為 install-time
的資產包可立即在應用程式啟動時使用,但您必須將其資產載入記憶體。請參閱將資產載入記憶體。
快速追蹤及隨選傳遞
這部分的內容適用於 fast-follow
及 on-demand
資產包。
檢查狀態
每個資產包會儲存在應用程式內部儲存空間的獨立資料夾中。請使用 isDone()
方法,判斷資產包是否已下載且可供使用,或是否發生錯誤。
監控下載內容
查詢 PlayAssetPackRequest
物件以監控要求的狀態:
// 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 does not mean that the request has completed, only that // the DOWNLOADING stage is finished. float progress = request.DownloadProgress; // Returns the status of the retrieval request. // If the request completed successfully, this value should be AssetDeliveryStatus.Available. // If an error occurred, this value should be AssetDeliveryStatus.Failed. AssetDelivery status = request.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.Failed: // Asset pack retrieval 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; } // Returns true if status is AssetDeliveryStatus.Available or AssetDeliveryStatus.Failed. bool done = request.IsDone; // If AssetDeliveryStatus.Failed, find more info about the error. AssetDeliveryErrorCode error = request.Error;
大型下載內容
大小超過 200 MB 的資產包只有在裝置連上 Wi-Fi 時才會自動下載。如果使用者未連上 Wi-Fi,PlayAssetPackRequest
狀態會設為 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; } }
取消要求 (僅限隨選)
如需在資產包下載之前取消要求,請在 PlayAssetPackRequest
物件上呼叫 AttemptCancel()
方法:
// Will only attempt if the status is Pending, Retrieving, or Available; otherwise // it will be a no-op. request.AttemptCancel(); // Check to see if the request was successful by checking if the error code is Canceled. if(request.Error == AssetDeliveryErrorCode.Canceled) { // Request was successfully canceled. }
將資產載入記憶體
完成要求後,請使用下列其中一個函式將資產載入記憶體:
- 使用
PlayAssetPackRequest.GetAssetLocation()
取得AssetLocation
物件。此物件會提供資產的路徑、位移和大小,方便資產從磁碟中載入。 - 如果資產是 AssetBundle,您可以使用簡便的方法
PlayAssetPackRequest.LoadAssetBundleAsync(assetPath)
。您傳入的資產路徑應符合從資產包內部到 AssetBundle 的路徑。這會回傳一個 AssetBundleCreateRequest。
以非同步方式要求資產包
在多數情況下,您應使用協同程式,以非同步方式要求資產包並監控進度,如下所示:
private IEnumerator LoadAssetPackCoroutine(string assetPackName) { PlayAssetPackRequest request = PlayAssetDelivery.RetrieveAssetPackAsync(assetPackName); while (!request.IsDone) { if(request.Status == AssetDeliveryStatus.WaitingForWifi) { var userConfirmationOperation = PlayAssetDelivery.ShowConfirmationDialog(); // 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(() => request.Status != AssetDeliveryStatus.WaitingForWifi); } // Use request.DownloadProgress to track download progress. // Use request.Status to track the status of request. yield return null; } if (request.Error != AssetDeliveryErrorCode.NoError) { // There was an error retrieving the pack. 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. Load the asset pack into memory. AssetBundleCreateRequest assetBundleCreateRequest = request.LoadAssetBundleAsync(path/to/exampleBundle); yield return assetBundleCreateRequest; AssetBundle assetBundle = assetBundleCreateRequest.assetBundle;
若要進一步瞭解如何處理錯誤,請參閱錯誤代碼清單。
其他 Play Core API 方法
以下列出一些其他您可能想在應用程式中使用的 API 方法。
擷取多個資產包
若要一次擷取多個資產包,請使用以下函式:
// assetPackNames is an array of strings corresponding to asset packs. PlayAssetPackBatchRequest batchRequest = PlayAssetDelivery.RetrieveAssetPackBatchAsync(<IListstring> assetPackNames);
檢查 Dictionary
的狀態可以監控每項要求的狀態:
// Dictionary of AssetPackStates, with the asset pack name as the key. Dictionary<string, PlayAssetPackRequest> requests = batchRequest.Requests; // Returns true if all requests are complete. bool requestComplete = batchRequest.IsDone;
檢查下載內容的大小
如要檢查資產包大小,請對 Google Play 發出非同步呼叫,並設定作業完成後的回呼方法:
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
您可以移除目前尚未載入記憶體的快速追蹤及隨選資產包。請進行以下非同步呼叫,並設定完成時的回呼方法:
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。