Use the steps in this guide to access your app’s asset packs from your Java code. If you haven't built an app bundle with asset packs, see Build for native or Java before going further.
Overview
The Play Core Java API
provides the
AssetPackManager
class for requesting asset packs, managing downloads, and accessing the assets.
You implement this API according to the delivery type of the asset pack you wish
to access. These steps are shown in the following flowchart.
Figure 1. Flow diagram for accessing asset packs
Install-time delivery
Asset packs configured as install-time
are immediately available at app
launch. Use the Java
AssetManager API to access assets
served in this mode:
import android.content.res.AssetManager; ... Context context = createPackageContext("com.example.app", 0); AssetManager assetManager = context.getAssets(); InputStream is = assetManager.open("asset-name");
Fast-follow and on-demand delivery
The following sections show how to get information about asset packs before
downloading them, how to call the API to start the download, and then how to
access the downloaded packs. 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
getPackLocation()
method to determine the root folder of an asset pack. This method returns the
following values:
Return value | Status |
---|---|
A valid AssetPackLocation object |
Asset pack root folder is ready for immediate access at assetsPath() |
null |
Unknown asset pack or assets are not available |
Get download information about asset packs
Apps are required to disclose the size of the download before fetching the asset
pack. Use the
getPackStates()
method to determine the size of the download and whether the pack is already
downloading.
Task<AssetPackStates> getPackStates(List<String> packNames)
getPackStates()
is an asynchronous method that returns a task. The task’s
result contains an
AssetPackStates
object. The
packStates()
method of an AssetPackStates
object returns a Map<String,
AssetPackState>
. This map contains the state of each requested asset
pack, keyed by its name:
Map<String, AssetPackState> AssetPackStates#packStates()
The final request is shown by the following:
final String assetPackName = "myasset"; assetPackManager .getPackStates(Collections.singletonList(assetPackName)) .addOnCompleteListener(new OnCompleteListener<AssetPackStates>() { @Override public void onComplete(Task<AssetPackStates> task) { AssetPackStates assetPackStates; try { assetPackStates = task.getResult(); AssetPackState assetPackState = assetPackStates.packStates().get(assetPackName); } catch (RuntimeExecutionException e) { Log.d("MainActivity", e.getMessage()); return; })
The following
AssetPackState
methods provide the size of the asset pack, the downloaded amount so far (if
requested), and the amount already transferred to the app:
To get the status of an asset pack, use the
status()
method, which returns the status as an integer that corresponds to a constant
field in the
AssetPackStatus
class. An asset pack that’s not installed yet has the status
AssetPackStatus.NOT_INSTALLED
.
If a request fails, use the
errorCode()
method, whose return value corresponds to a constant field in the
AssetPackErrorCode
class.
Install
Use the
fetch()
method to download an asset pack for the first time or call for the update of an
asset pack to complete:
Task<AssetPackStates> fetch(List<String> packNames)
This method returns an
AssetPackStates
object containing a list of packs and their initial download states and sizes.
If an asset pack requested via fetch()
is already downloading, the download
status is returned and no additional download is started.
Monitor download states
You should implement a listener
to track the installation progress of asset
packs. The status updates are broken down per pack to support tracking the
status of individual asset packs. You can start using available asset packs
before all other downloads for your request have completed.
void registerListener(
AssetPackStateUpdatedListener
listener)
void unregisterListener(AssetPackStateUpdatedListener listener)
Large downloads
If the download is larger than 150 MB and the user is not on Wi-Fi, the download
does not start until the user explicitly gives their consent to proceed with the
download using a mobile data connection. Similarly, if the download is large and
the user loses Wi-Fi, the download is paused and explicit consent is required to
proceed using a mobile data connection. A paused pack has state
WAITING_FOR_WIFI
. To trigger the UI flow to prompt the user for consent, use
the
showCellularDataConfirmation()
method.
Note that if the app does not call this method, the download is paused and will resume automatically only when the user is back on a Wi-Fi connection.
The following is an example implementation of a listener:
assetPackStateUpdateListener = new AssetPackStateUpdateListener() { @Override public void onStateUpdate(AssetPackState assetPackState) { switch (assetPackState.status()) { case AssetPackStatus.PENDING: Log.i(TAG, "Pending"); break; case AssetPackStatus.DOWNLOADING: long downloaded = assetPackState.bytesDownloaded(); long totalSize = assetPackState.totalBytesToDownload(); double percent = 100.0 * downloaded / totalSize; Log.i(TAG, "PercentDone=" + String.format("%.2f", percent)); break; case AssetPackStatus.TRANSFERRING: // 100% downloaded and assets are being transferred. // Notify user to wait until transfer is complete. break; case AssetPackStatus.COMPLETED: // Asset pack is ready to use. Start the game. break; case AssetPackStatus.FAILED: // Request failed. Notify user. Log.e(TAG, assetPackState.errorCode()); break; case AssetPackStatus.CANCELED: // Request canceled. Notify user. break; case AssetPackStatus.WAITING_FOR_WIFI: if (!waitForWifiConfirmationShown) { assetPackManager.showCellularDataConfirmation(MainActivity.this) .addOnSuccessListener(new OnSuccessListener<Integer> () { @Override public void onSuccess(Integer resultCode) { if (resultCode == RESULT_OK) { Log.d(TAG, "Confirmation dialog has been accepted."); } else if (resultCode == RESULT_CANCELED) { Log.d(TAG, "Confirmation dialog has been denied by the user."); } } }); waitForWifiConfirmationShown = true; } break; case AssetPackStatus.NOT_INSTALLED: // Asset pack is not downloaded yet. break; } } }
Alternatively, you can use the
getPackStates()
method to get the status of current downloads.
AssetPackStates
contains the download progress, download status, and any failure error codes.
Access asset packs
You can access an asset pack using file system calls after the download request
reaches the
COMPLETED
state. Use the
getPackLocation()
method to get the root folder of the asset pack.
Assets are stored in the assets
directory within the asset pack root
directory. You can get the path to the assets
directory by using the
convenience method
assetsPath()
.
Use the following method to get the path to a specific asset:
private String getAbsoluteAssetPath(String assetPack, String relativeAssetPath) { AssetPackLocation assetPackPath = assetPackManager.getPackLocation(assetPack); if (assetPackPath == null) { // asset pack is not ready return null; } String assetsFolderPath = assetPackPath.assetsPath(); // equivalent to: FilenameUtils.concat(assetPackPath.path(), "assets"); String assetPath = FilenameUtils.concat(assetsFolderPath, relativeAssetPath); return assetPath; }
Other Play Core API methods
The following are some additional API methods you may want to use in your app.
Cancel request
Use
cancel()
to cancel an active asset pack request. Note that this request is a best-effort
operation.
Remove an asset pack
Use
removePack()
to schedule the removal of an asset pack.
Get locations of multiple asset packs
Use
getPackLocations()
to query the status of multiple asset packs in bulk, which returns a map of
asset packs and their locations. The map returned by getPackLocations()
contains an entry for each pack that is currently downloaded and up-to-date.
Next step
Test Play Asset Delivery locally and from Google Play.