App Bundles and Dynamic feature modules — A silver bullet for bloated Apks

Tomoaki Imai
AndroidPub
Published in
4 min readMay 15, 2018
Image from https://developer.android.com/guide/app-bundle/configure

Google announced a new feature called Android App Bundles and Dynamic feature modules at Google I/O 2018. I played around with both features and felt this would definitely improve the installation conversion rate if Apk size is rather big. Here’s a note of what this both features do and what you need to prepare for them.

Android App Bundles

Android App Bundle is a new upload format(aab) which contains all types of codes and resources. Once you upload the aab file to PlayStore, PlayStore will build Apks that are optimized to each device or OS version. I guess Google is planning to make this format as default, but as of May 2018, you need to use Android Studio Canary 14 to build aab file. You can either build the app with Android Studio or use commandline ./gradlew bundleDebug.

By the way, I took a look into the aab file and found that most files were Protocol Buffer binary files.

The benefit of using Android App Bundles is that you can reduce the app size without any effort. You can check a list of Apks by using bundletool

Here’s the result of mine.

Since my project contains NDK, it has CPU language files. There are about 4MB of difference between x86 and armabi. If I consider launguage resources and screen density sizes, the total saving of Apk size would be roughly 5–10 MB. Yay, it’s a big difference!

Dynamic feature modules

Dynamic feature modules is one kind of Bundle file. If you set a module as Dynamic feature file, you can exclude this module from the base app, and let users can download it when required. This is especially useful when your app contains features not every user would always uses.

The step to make your feature to Dynamic feature modules is very close to creating Library module. Here are some differences:

  • Instead of com.android.library, apply com.android.dynamic-feature
// bundle.gradle
apply plugin: 'com.android.dynamic-feature'
dependencies {
implementation project(':app')
}
  • Add Dynamic feature module dependencies to the base Module
// app/bundle.gradle
android {
dynamicFeatures = [":name_of_module"]
}
  • Add a module setting on Dynamic feature module’s Android manifest.
// name_of_module/main/AndroidManifest.xml
<dist:module
dist:onDemand="true" // Dynamic Delivery
dist:title="@string/name_of_module" // Title shown when downloading a module. Requires the definition in base module's strings.xml
<dist:fusing include="true" /> // True if include this module in 4.4
</dist:module>

This is it!

To download dynamic feature modules from your app, you need to setup Play Core Library.

This library helps you manage a downloading process like below:

private val listener = SplitInstallStateUpdatedListener { state ->
state.moduleNames().forEach { name ->
when (state.status()) {
SplitInstallSessionStatus.DOWNLOADING -> {
displayLoadingState(state, "Downloading $name")
}
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
manager = SplitInstallManagerFactory.create(this)
}
override fun onResume() {
manager.registerListener(listener)
super.onResume()
}

Here’s a sample project from Google.

Questions I had for Dynamic feature modules

I got some questions about Dynamic features modules answered at Office Hour in Google I/O.

How does Dynamic feature modules behave in your local debug build?

It works just like a normal library. You can either Run from Android Studio or assembleDebug command. In the code below, SplitInstallManager.installedModules always returns true.

val manager = SplitInstallManagerFactory.create(this)...
private fun loadAndLaunchModule(name: String) {
updateProgressMessage("Loading module $name")
if (manager.installedModules.contains(name)) { // always true
updateProgressMessage("Already installed")
onSuccessfulLoad(name, launch = true)
return
}
...

If you want to exclude Dynamic Feature modules from your debug build you can setup from the configuration.

You can select which modules to be included

Can you test Dynamic feature modules locally?

No. Currently You have to use Internal test of PlayStore to test a behavior of the downloading process.

You can find it at PlayStore

Does it affect build time or runtime?

Actually build time should improve because by modularizing features you can run parallel gradle build. On the other hand, runtime will have some overhead because it looks for dex files.

Can we deploy from CI tools?

Yes. App Bundle’s bundletool can create Apks out of the box. You can perform Apk builds on CI and deploy them.

bundletool build-apks --bundle=/MyApp/my_app.aab 
--output=/MyApp/my_app.apks
--ks=/MyApp/keystore.jks
--ks-pass=file:/MyApp/keystore.pwd
--key-pass=file:/MyApp/key.pwd

Prepare for App Bundle and Dynamic feature modules

When you develop your app for long term, usually Apk size becomes bloated. App Bundle and Dynamic feature modules could be a silver bullet to reduce Apk size and we should definitely prepare for them. Especially for Dynamic feature modules, designing a modularized architecture will be quite important.

--

--

Tomoaki Imai
AndroidPub

CTO at Noxx https://www.noxx.net/ AI hiring tool. FullStack developer and leader. Love to share ideas about software development. https://github.com/tomoima525