Android App Bundle is a new format for you to build and package your app. A build tool packages a traditional app into an app bundle based on the ABI architecture, screen density, and language. When a user downloads your app, HUAWEI AppGallery Connect provides a sub app bundle that adapts only to the user's device type, thereby reducing network data and device storage space, with which the same service functions can be provided.

After you integrate the Dynamic Ability SDK into an Android project, your app can interact with AppGallery Connect and use App Bundle to dynamically load some modules in the app.

What You Will Learn

Hardware Requirements

Software Requirements

Creating an Android Project

  1. Open Android Studio and go to File > New > New Project.
  2. On the Phone and Tablet tab page, click Empty Activity and Next.
  3. Configure project attributes, such as the project name, package name, and API level.
  4. Click Finish.
    In this example, the module is of the Application type in Android. In other words, any module of the Application type can be a Base App.
  1. Open the created Android project and go to File > New > New Module.
  2. Select Dynamic Feature Module and click Next.
  3. Set Base application module to the Base App you have created. Set Module name and Package name. Click Next.
  4. Set Module title (visible to users) and Install-time inclusion.
  5. Click Finish.

Checking Configuration Items

  1. Check the build.gradle file in Base App. In the file, the Android closure contains the following configuration:
    android { // Ignore irrelevant configurations. // Base App is associated with Dynamic Feature Module. dynamicFeatures = [":demofeature"] }
  2. Check the build.gradle file in Dynamic Feature Module. In the file, the dependencies closure contains the following configuration:
    dependencies { // Ignore irrelevant configurations. // The module depends on Base App. implementation project(':app') }
  3. The preceding configurations are automatically completed when Dynamic Feature Module is created.

Importing the Dynamic Ability SDK

  1. Add the following dependency to the build.gradle file of Base App in the project:
    dependencies { implementation 'com.huawei.hms:dynamicability:' ... }
  2. Set Application for Base App in the project, override the attachBaseContext() method, and add the SDK startup code.
    public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Start the Dynamic Ability SDK. FeatureCompat.install(base); } }
  3. Add the following configuration to the activity in the feature:
    @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); FeatureCompat.install(newBase); }

Loading Dynamic Feature Module in Base App

After you import and start the Dynamic Ability SDK, you need to call the SDK to load Dynamic Feature Module based on service requirements so that your app can dynamically load features as required.

  1. Instantiate FeatureInstallManager to manage the entire loading process in a unified manner.
    FeatureInstallManager mFeatureInstallManager; mFeatureInstallManager = FeatureInstallManagerFactory.create(this);
  2. Create an instance of FeatureInstallRequest and specify loading information. In this request, you can specify one or more feature names. Example:
    FeatureInstallRequest request = FeatureInstallRequest.newBuilder() // Add the name of a dynamic feature. .addModule("SplitSampleFeature01") .build();
  3. Register a listener for the dynamic feature loading task to monitor the task status. The status may be successful or failed. Example:
    task.addOnListener(new OnFeatureSuccessListener<Integer>() { @Override public void onSuccess(Integer integer) { Log.d(TAG, "load feature onSuccess.session id:" + integer); } }); task.addOnListener(new OnFeatureFailureListener<Integer>() { @Override public void onFailure(Exception exception) { if (exception instanceof FeatureInstallException) { int errorCode = ((FeatureInstallException) exception).getErrorCode(); Log.d(TAG, "load feature onFailure.errorCode:" + errorCode); } else { exception.printStackTrace(); } } });
  4. Register a listener for the FeatureInstallManager object to listen to multiple loading states. The InstallStateListener listener registered for FeatureInstallManager returns the FeatureInstallSessionState object. This object contains the actual loading status. Therefore, in actual development, you need to register only one listener, and then perform proper actions based on the value of InstallState in the listener. This reduces redundant code. The implementation is as follows:
    Create an instance of InstallStateListener.
    private InstallStateListener mStateUpdateListener = new InstallStateListener( { @Override public void onStateUpdate(InstallState state) { Log.d(TAG, "onStateUpdate " + state); if (state.status() == FeatureInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { try { boolean result = mFeatureInstallManager.triggerUserConfirm(state, CancelActivity.this, 1); } catch (IntentSender.SendIntentException e) { e.printStackTrace(); } return; } if (state.status() == FeatureInstallSessionStatus.REQUIRES_PERSON_AGREEMENT) { try { boolean result = mFeatureInstallManager.triggerUserConfirm(state,Activity.this, 1); } catch (IntentSender.SendIntentException e) { e.printStackTrace(); } return; } if (state.status() == FeatureInstallSessionStatus.INSTALLED) { Log.i(TAG, "installed success ,can use new feature"); makeToast("installed success , can test new feature "); return; } if (state.status() == FeatureInstallSessionStatus.UNKNOWN) { Log.e(TAG, "installed in unknown status"); makeToast("installed in unknown status "); return; } if (state.status() == FeatureInstallSessionStatus.DOWNLOADING) { Log.d(TAG, "installed in Downloading "+ state.bytesDownloaded() * 100 / state.totalBytesToDownload()); return; } if (state.status() == FeatureInstallSessionStatus.FAILED) { Log.e(TAG, "installed failed, errorcode : " + state.errorCode()); makeToast("installed failed, errorcode : " + state.errorCode()); return; } } };
  5. Register and deregister the listener.

    @Override protected void onResume() { super.onResume(); if (mFeatureInstallManager != null) { mFeatureInstallManager.registerInstallListener( installStateListener); } } @Override protected void onPause() { super.onPause(); if (mFeatureInstallManager != null) { mFeatureInstallManager.unregisterInstallListener( installStateListener); } }
  6. Start Dynamic Feature Module. Then, you can start Dynamic Feature Module in Base App. Example:
    startActivity(new Intent(this, Class.forName("com.huawei.android.demofeature.TestActivity")));

In this section, you need to build a complete APK, app bundle, and custom app bundle.

Building a Bundle

Open Android Studio and go to Build > Build Bunlde(s) / APK(s) > Build Bundle(s).

The app-debug.aab file is generated in build > outputs > bundle > debug.

Building a Custom App Bundle

By default, Android Studio automatically splits your app based on the ABI architecture, screen density, and language. If you want to customize the splitting dimension, add a control switch to android.bundle in the app/build.gradle file.

bundle { language { enableSplit = false } density { enableSplit = true } abi { enableSplit = true } }

If enableSplit under language is set to false, Android Studio packages all language resources to base.apk during building.

You cannot install and test the app bundles locally through the .aab files generated, but you need to use the Bundletool to convert the .aab file into an APK set. The BundleTool is an open-source command line tool of Google. You can upload the .aab file to AppGallery Connect, and AppGallery Connect will automatically call the BundleTool to convert the file. This section describes how to convert the .aab file locally using the BundleTool.

Converting an .aab File to APKs

java -jar bundletool-all-0.10.2.jar build-apks --bundle=app-debug.aab --output=aab.apks

In the command, bundle indicates the path of the .aab file and output indicates the path of the generated .apks file.
Change the file name extension .apks to .zip and decompress the .zip file to obtain the .apk files.

Installing a Bundle

Find the master package and the screen density package, language package, and ABI architecture package that adapt to your mobile phone, and install and test the bundle. In this example, the following packages are used: base-master.apk (master package), base-xxxhdpi.apk (screen density package), and base-zh.apk (language package), but no SO file (ABI architecture package) is available. Install the packages on the mobile phone to verify the functions.

adb install-multiple .\outputs\bundle\debug\splits\base-master.apk .\outputs\bundle\debug\splits\base-xxxhdpi.apk .\outputs\bundle\debug\splits\base-zh.apk

Converting an .aab File to a Complete APK

Android versions earlier than 5.0 do not support app bundles. In some scenarios, a complete APK is required so that you need to call the BundleTool to convert the .aab file to a complete APK. The method is as follows:

java -jar bundletool-all-0.10.2.jar build-apks --bundle= app-debug.aab --output=aab-un.apks --mode=universal

Change the file name extension .apks to .zip and then decompress the .zip package. The .apk file is generated as follows.

Installing a Complete APK

adb install universal.apk

Click here to refer to the guide about how to connect to AppGallery Connect.

Congratulations! You have completed the first project of App Bundle and learned how to:

For more information about APIs of Dynamic Ability, please refer to API Reference.

To download the sample code, please click the button below:


Code copied