AAB

Android App Bundle is a new official distribution format for Android that allows you to develop and distribute your apps in a more efficient way. With the Android App Bundle, you can more easily deliver a great experience in smaller apps, increasing installation success and reducing uninstalls. The conversion process is easy and convenient. You don’t have to refactor your code to start taking advantage of smaller apps. By switching to this format, you can experience and benefit from modular application development and customizable functionality delivery.

Play Asset Delivery

Play Asset Delivery (PAD) brings the benefits of App Bundle to games. It allows games over 150 MB to replace older extension files (OBBs) by publishing a single artifact to Play that contains all the resources needed for the game. The PAD offers a flexible distribution model, automatic update, compression, and incremental patching, and is free to use. With PAD, all resource packs are hosted and provided on Google Play, so you don’t have to use a content distribution Network (CDN) to deliver game resources to your players.

Play Asset Delivery uses resource bundles, which consist of resources (such as textures, shaders, and sounds) but do not contain executable code. With Dynamic Delivery, you can customize how and when individual resource bundles are downloaded to the device in three distribution modes: install-time distribution, fast-follow distribution, and on-demand distribution.

Distribution pattern

Install-time resource packages are distributed when users install applications. These resource bundles are provided as split APKs, which are part of the APK set. They are also called “up front” resource bundles; You can use these resource packs immediately upon application launch. These resource packs increase the size of the apps listed on the Google Play Store. Users cannot modify or delete these resource bundles.

The fast-follow resource pack is automatically downloaded immediately after the user installs the app; Users don’t need to open the app to start the fast-follow download. Such downloads do not prevent users from accessing the application. These resource packs increase the size of the apps listed on the Google Play Store.

On-demand resource bundles are downloaded while the application is running.

The Google Play Store provides resource packs configured for fast follow and on-demand in the form of archived files rather than split APKs. These resource bundles are then deployed in the application’s internal storage space. You can use the Play Core API to query the location of resource bundles provided in this way. The application cannot assume the existence or location of these files, as they may be deleted by the user or moved between game sessions by the Play Core SDK. Although these files can be written by the application, you should treat them as read-only because the resource pack patch depends on the integrity of these files.

Resource update

When an application is updated, the Install-Time Asset Pack is updated as part of the underlying application update (no developer action required).

For application updates to the fast-follow and On-Demand Asset Pack, follow these steps:

  • 1. The system downloads the patches (including all assets) to a secure location on the device.
  • 2. Update application binary files; This includes all Install-Time Asset packs.
  • 3. All Asset Packs downloaded previously become invalid.
  • 4. Copy the patches of the assets and apply them to the assets stored in the internal application storage space.

In most cases, when the user opens the game, the overall update is complete and the user can immediately start playing the updated version. In rare cases, the application binaries may have been updated by the time the user opens the application, but the patching process for the asset has not been completed, so the user cannot access the asset. To deal with such situations, you need to provide “updating” interface elements for these assets, or build logic to handle invalid resources that are not yet accessible. Since the application binaries are not updated until all Asset Pack types have been downloaded, the application of the patch is done locally, offline, and should be done quickly.

Texture compression format localization

Texture compression is a lossy image compression that allows the GPU to render directly from compressed textures using dedicated hardware, thereby reducing the amount of texture memory and memory bandwidth required. With texture compression format location, you can add textures compressed in multiple texture compression formats to the Android App Bundle and rely on Google Play to automatically provide resources in the best texture compression format for each device.

App Version Update

Once a new version of the app is uploaded to Google Play, users can open the previous version of the app if they haven’t updated it on their device. In this case, the application can choose to force or suggest Updates by calling the In-App Updates API, if necessary. With this API, you can trigger updates from within your app, rather than having users trigger updates from the Google Play Store.

Download size cap

Asset Pack is ideal for larger games due to its high size ceiling:

  • 1. Each fast-follow and On-Demand Asset Pack has a maximum download size of 512 MB.
  • 2. The total download size of all Install-Time Asset Packs is capped at 1 GB.
  • 3. The maximum download size for all Asset Packs in an Android App Bundle is 2 GB.
  • You can use up to 50 resource bundles in an Android App Bundle.

If you are using a texture compression format location, these download restrictions apply to each unique texture format.

Build for Java code

You can follow these steps to build Play Asset Delivery into your project’s Android App Bundle. You don’t need Android Studio to perform these steps.

  • 1. Import the Play Core library into the project.
// In your app’s build.gradle file:. dependencies {// This dependency is downloaded from the Google’s Maven repository.
    // So, make sure you also include that repository in your project's build.gradle file.
    implementation 'com. Google. Android. Play: core: 1.10.0'

    // For Kotlin users also add the Kotlin extensions library for Play Core:
    implementation 'com. Google. Android. Play: the core - KTX:, version 1.8.1'. }Copy the code

The Play Core KTX library is optional and provides a version of the Kotlin coroutine for asynchronous method calls in the regular Play Core library, as well as other useful extensions that make using the API from Kotlin more handy.

  • Update the Android Gradle plugin to 4.0.0 or higher in the build.gradle file of your project.
  • 3. Create a directory for Asset Pack in the top-level directory of your project. This directory name will be used as the Asset Pack name. The Asset Pack name must start with a letter and contain only letters, numbers, and underscores.
  • In the Asset Pack directory, create a build.gradle file and add the following code. Be sure to specify the name of the Asset Pack and specify only one distribution type:
// In the asset pack’s build.gradle file:
apply plugin: 'com.android.asset-pack'

assetPack {
    packName = "asset-pack-name" // Directory name for the asset pack
    dynamicDelivery {
        deliveryType = "[ install-time | fast-follow | on-demand ]"}}Copy the code
  • 5. Add the name of each Asset Pack in your project to the build.gradle file, as shown below:
// In the app build.gradle file:
android {
    ...
    assetPacks = [":asset-pack-name".":asset-pack2-name"]}Copy the code
  • 6. In settings.gradle, add all Asset packs in your project as shown below:
// In the settings.gradle file:
include ':app'
include ':asset-pack-name'
include ':asset-pack2-name'
Copy the code
  • 7. In the Asset Pack directory, create a subdirectory SRC /main/assets.

  • 8. Place the assets in the SRC /main/assets directory. You can also create subdirectories here. The directory structure for your application should now look like this:

    • 1.build.gradle
    • 2.settings.gradle
    • 3.app/
    • 4.asset-pack-name/build.gradle
    • 5.asset-pack-name/src/main/assets/your-asset-directories
  • 9. Build Android App bundles using Gradle. In the generated app bundle, the root directory now contains the following:

    • 1. The asset – pack – name/manifest/AndroidManifest. XML: configuration asset pack identifier and distribution pattern
    • Asset-pack-name /assets/your-asset-directories: This directory contains all assets that are being distributed as part of the Asset pack

Gradle generates a list for each Asset Pack and outputs the assets/ directory for you.

  • 10. (Optional) Configure App Bundle to support different texture compression formats.

Common texture compression formats:

  • DDS or S3TC: sometimes called DXTC or DXTn. OpenGL supports three forms of this format.
  • ETC1: Most devices support this format. This format does not support transparency, but the game can use a second texture file for the Alpha channel component.
  • ETC2: All devices that support GLES3 support this format.
  • PVRTC: A common format for iOS games, supported on some Android devices.
  • ASTC: A new format designed to replace the previous format. It is more flexible than the previous format because it supports a variety of block sizes. Using this format will help you optimize the size of your game.

Supported formats and percentage of devices that support them:

Play Core API integration

Be sure to add the Play Core library to your project first.

The Play Core Java API provides the AssetPackManager class for requesting resource packs, managing downloads, and getting resources. Be sure to add the Play Core library to your project first. You can implement this API based on the distribution type of the resource bundle you want. These steps are shown in the following flow chart.

Note: The API used to get the Install-Time Asset Pack is different from the API used to get the fast-follow and On-Demand Asset Pack.

Distribution at installation

Install-time resource packages can be used immediately after the application starts. Get the assets provided in this mode using the Java AssetManager API:

importandroid.content.res.AssetManager; . Context context = createPackageContext("com.example.app".0);
AssetManager assetManager = context.getAssets();
InputStream is = assetManager.open("asset-name");
Copy the code

Fast-track distribution and on-demand distribution

The following sections describe how to get information about an Asset Pack before it is downloaded, how to call the API to start the download, and how to get the downloaded Asset Pack afterwards. These sections apply to the fast-follow and On-Demand Asset Pack.

Check the status

Each resource bundle is stored in a separate folder within the application’s internal storage space. Use the getPackLocation() method to determine the root folder of the Asset Pack. This method returns the following values:

  • The valid AssetPackLocation object > resource bundle root folder is located at assetsPath() and is now available immediately
  • Null > Unknown Asset Pack or Asset unavailable

Note: Do not rely on the Asset Pack location cached between application launches. The application should always check for the presence of the Asset Pack at every startup. The Asset Pack may become invalid due to application updates or user purging of application data.

Gets download information about resource packs

Before extracting resource bundles, the application must disclose the size of the downloaded content. Use the getPackStates() method to determine the size of the downloaded content and whether the resource bundle is already being downloaded.

Task<AssetPackStates> getPackStates(List<String> packNames)
Copy the code

GetPackStates () is an asynchronous method used to return tasks. The result of this task contains an AssetPackStates object. The packStates() method of the AssetPackStates object returns a Map

. This map contains the state of each Asset Pack requested, keyed by its name:
,>

Map<String, AssetPackState> AssetPackStates#packStates()
Copy the code

The final request looks like this:

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;
            })
Copy the code

The following AssetPackState methods provide the size of the resource bundle, how much data has been downloaded to date (if requested), and how much data has been transferred to the application:

  • totalBytesToDownload()
  • bytesDownloaded()
  • transferProgressPercentage()

To get the status of the resource bundle, use the status() method, which returns the status as an integer corresponding to a constant field in the AssetPackStatus class. An uninstalled resource bundle is in assetPackStatus.not_installed state.

If the request fails, use the errorCode() method, whose return value corresponds to a constant field in the AssetPackErrorCode class.

The installation

Use the fetch() method to download the resource pack for the first time, or request a resource pack update to complete the operation:

Task<AssetPackStates> fetch(List<String> packNames)
Copy the code

This method returns an AssetPackStates object containing a list of resource bundles and their initial download status and size. If the Asset Pack requested through fetch() is already downloading, the download status is returned and no additional downloads are started.

** Note: ** In most cases, you need to implement listeners to track the download and installation process, as described in the next section.

Monitoring download status

You should implement a Listener to track the installation progress of Asset Pack. Status updates are broken down by Asset Pack to support tracking the status of individual Asset Packs. You can start using the resource packs that are already available before all other requested downloads are complete.

  • void registerListener(AssetPackStateUpdatedListener listener)
  • void unregisterListener(AssetPackStateUpdatedListener listener)

Note: After the user installs or updates the app, the Play Store will automatically trigger the download of any fast-follow resource packs. However, these resource bundles may not be immediately available to users. You must check the status of the Fast-Follow Asset Pack every time your app starts. If the download is in progress, monitor it with a listener. If the download has been cancelled or paused, you can use the fetch() method to resume the download, as described in the Installation section.

Download content is large

If the download exceeds 150MB and the user is not connected to WLAN, the download will not begin until the user has expressly agreed to continue the download using a mobile network connection. Similarly, if the download content is large and the user is disconnected from the WLAN, the download will be suspended and the user can use the mobile network connection to continue the download. The paused Asset Pack state is WAITING_FOR_WIFI. If you need to prompt the user agrees to trigger the interface process, please use the showCellularDataConfirmation () method.

Note that if the application does not call this method, the download is paused and automatically resumes only when the user reconnects to WLAN.

Here 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; }}}Copy the code

Alternatively, you can use the getPackStates() method to get the current download status. AssetPackStates contains download progress, download status, and error codes for any failures.

Obtaining resource packages

After the download request has reached the COMPLETED state, you can use the file system call to retrieve the resource bundle. Use the getPackLocation() method to get the root folder of the resource bundle.

Resources are stored in assets in the root directory of the resource package. You can use the handy method assetsPath() to get the path to assets. Get the path to a particular asset using:

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;
}
Copy the code

Cancel the request

Cancel a valid resource bundle request with cancel(). This request is a best effort.

Removing resource packs

Use removePack() to arrange the removal of resource packs.

Gets the location of multiple resource bundles

Batch query the status of multiple resource bundles using getPackLocations(), which returns a map of the resource bundle and its location. The map returned by getPackLocations() contains the entry for each Asset Pack that is currently downloaded and in its latest state.