When integrating asset delivery, Unity games can access asset packs using Addressables or AssetBundles. Addressables are the more recent and recommended asset delivery solution for games built with Unity 2019.4 or higher, while AssetBundles provide support of asset packs in Unity 2017.4 and 2018.4.
Unity Addressables
Games built with Unity 2019.4 or higher should use Addressables for asset delivery on Android. Unity provides a Play Asset Delivery (PAD) API for handling Android asset packs using Addressables. For information about using Addressables, see the following:
- Addressables for Android package
- PAD guide for Unity
- PAD API for Unity reference documentation
Use AssetBundle files
Games built with Unity 2017.4 and 2018.4 can use AssetBundle files for asset delivery on Android. Unity AssetBundle files contain serialized assets that can be loaded by the Unity engine while the app is running. These files are platform-specific (for example, built for Android) and can be used in combination with asset packs. Most commonly, one AssetBundle file is packaged into a single asset pack, with the pack using the same name as the AssetBundle. If you want more flexibility in creating an asset pack, configure the asset pack using the API.
At runtime, use the Play Asset Delivery for Unity class to retrieve an AssetBundle packaged in an asset pack.
Prerequisites
Download the latest release of Play Asset Delivery Unity Plugin from Google packages for Unity.
Configure AssetBundles using the UI
Configure each AssetBundle in an asset pack:
- Select Google > Android App Bundle > Asset Delivery Settings.
- To select folders that directly contain AssetBundle files, click Add Folder.
For each bundle, change the Delivery Mode to Install Time, Fast Follow, or On Demand. Resolve any errors or dependencies and close the window.
Select Google > Build Android App Bundle to build the app bundle.
(Optional) Configure your app bundle to support different texture compression formats.
Configure asset packs using the API
You can configure asset delivery through editor scripts which can be run as part of an automated build system.
Use the
AssetPackConfig
class to define which assets to include in an Android App Bundle build, as well
as the delivery mode of the assets. These asset packs do not need to contain
an 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); }
You can also use the static
BuildBundle
method in the Bundletool
class to generate an Android App Bundle with asset
packs, given
BuildPlayerOptions
and
AssetPackConfig
.
For a guided tutorial, see the Using Play Asset Delivery in Unity games Codelab.
Integrate with Play Asset Delivery Unity API
The Play Asset Delivery Unity API provides the functionality for requesting asset packs, managing downloads, and accessing the assets. Make sure to Add the Unity plugin into your project first.
The functions you use in the API depend on how you created the asset packs.
If you created asset packs using the plugin UI, select Plugin-configured asset packs.
If you created asset packs using the API (or plugin UI), select API-configured asset packs.
The API is similar regardless of the delivery type of the asset pack you wish to access. These steps are shown in the following flowchart.
Retrieve an asset pack
Import the
Play Asset Delivery library
and call the
RetrieveAssetPackAsync()
method to download an asset pack if the latest version of the pack isn't already
available on disk.
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 delivery
An asset pack configured as install-time
is immediately available at app
launch, but you need to load its assets into memory. See
Load assets into memory.
Fast-follow and on-demand delivery
These sections apply to fast-follow
and on-demand
asset packs.
Check status
Each asset pack is stored in a separate folder in the app's internal storage.
Use the
isDone()
method to determine if an asset pack has already been downloaded and is
available, or if an error occurred.
Monitor the download
Query the
PlayAssetPackRequest
object to monitor the
status
of the request:
// 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;
Large downloads
Asset packs larger than 200MB can download automatically, but only if the device
is connected to Wi-Fi. If the user is not on Wi-Fi, the PlayAssetPackRequest
status is set to
AssetDeliveryStatus.WaitingForWifi
and the download is paused. In this case, either wait until the device connects
to Wi-Fi, resuming the download, or prompt the user for approval to download the
pack over a cellular connection.
Required user confirmation
If a pack has the AssetDeliveryStatus.RequiresUserConfirmation
status, the
download won't proceed until the user accepts the dialog that is shown with
PlayAssetDelivery.ShowConfirmationDialog()
. This status can arise if the app
is not recognized by Play. Note that calling
PlayAssetDelivery.ShowConfirmationDialog()
in this case causes the app to
be updated. After the update, request the assets again.
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; } }
Cancel a request (on-demand only)
If you need to cancel the request before the asset packs are downloaded, call
the
AttemptCancel()
method on the PlayAssetPackRequest
object:
// 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. }
Load assets into memory
Once the request completes, use one of these functions to load assets into memory:
- Use
PlayAssetPackRequest.GetAssetLocation()
to get anAssetLocation
object. This provides the path, offset, and size of the asset so that it can be loaded from disk. - If the asset is an AssetBundle, you can use the convenience method
PlayAssetPackRequest.LoadAssetBundleAsync(assetPath)
. The asset path you pass in should correspond to the path to the AssetBundle from within the asset pack. This will return an AssetBundleCreateRequest.
Request asset packs asynchronously
In most cases, you should use Coroutines to request asset packs asynchronously and monitor progress, as shown by the following:
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;
For more information on handling errors, see the list of error codes.
Other Play Core API methods
The following are some additional API methods you may want to use in your app.
Retrieve multiple asset packs
To retrieve multiple asset packs at once, use the following function:
// assetPackNames is an array of strings corresponding to asset packs. PlayAssetPackBatchRequest batchRequest = PlayAssetDelivery.RetrieveAssetPackBatchAsync(<IListstring> assetPackNames);
Monitor the statuses of each request by inspecting the Dictionary
of states:
// 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;
Check download size
Check the size of an asset pack by making an asynchronous call to Google Play and setting a callback method for when the operation completes:
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(); } }
Remove AssetBundles
You can remove fast-follow and on-demand asset packs that are not currently loaded into memory. Make the following asynchronous call and set a callback method for when it completes:
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. } };
Next steps
Test asset delivery locally and from Google Play.