In 2018, Google Play introduced a new application serving model, the Dynamic Delivery, to help generating and serving optimized APKs based on the device configuration. It uses the Android App Bundle format to dynamically generate the APK for each device variant, which is much better than manually generating them.

Dynamic Delivery not only optimizes the APK, it also enables another feature in our apps: the Dynamic Feature Modules. These dynamic modules can be automatically installed based on device configuration or downloaded later, after the app is already installed and running.

In this article, we will see how to create a Dynamic Feature from scratch, showing the step-by-step, the particularities and common issues. For more information about the technical points of Dynamic Delivery and Android App Bundle, please visit the official documentation.

Main objective

The main objective is creating a simple application with a Dynamic Feature Module which will be manually downloaded by the user. This scenario represents a feature that may be used only a few times, or that might not be needed right away. Modules such as paid functionalities, chat support and plugins are examples of possible On-demand Dynamic Features.

I’m currently using Dynamic Feature in my to-do application, Alkaa. There is a Tracker to show a chart informing the user about the tasks completed during a period of time.

Requirements

Unfortunately, your application can only connect to Google Play and download the Dynamic Feature Module after being published. To publish your Android App you will need to subscribe on Google Play. For more information about how to publish, please take a look at the official documentation. Feel free to clone and publish the sample application provided at the end of this article, just do not forget to change the package name.

Hands-on

Creating the Dynamic Feature module

During the hands-on, I will use the repository below. All the code is available there, feel free to use the code as you want. The start point is a template application with an empty Activity.

Let’s create our Dynamic Feature. In order to create you need to access:

File > New > New Module... > Dynamic Feature Module

Dynamic Feature Module creation option

In the next screen, you will choose the Module name, package, and the minimum API level. After that, we will choose the Module Title, which is the name that identifies the module for the user on Google Play.

Install-time inclusion defines how and when this Dynamic Feature will be available for the user. In this example, we will use the default, Do not include module at install-time (on-demand only). For more information about other inclusion options, please refer to official docs.

Pre-Lollipop (API 21) does not support Dynamic Features, you need to specify if the feature should be available at install-time via Fusing preference. In this example, we will include these devices.

Module Download Options

Now just finish your module creation and the project will create your new module. It is possible to notice some differences between a Dynamic Feature module and a regular Feature one:

Plugin in ondemand/build.gradle is com.android.dynamic-feature

is The dependency between :app and :ondemand is inverted. Meaning that :ondemand knows :app , but not the opposite

and is inverted. Meaning that knows , but not the opposite Dynamic Feature AndroidManifest.xml containing the preferences:

The app/build.gradle adds the Dynamic Feature:

Downloading the Dynamic Feature on application

Now we will add the Play Core Library to connect to Google Play. This dependency needs to be added in app/build.gradle to download and install the module and in ondemand/build.gradle to load the resources after the installation.

implementation 'com.google.android.play:core:1.6.4'

In order to access the code and resources from the downloaded module, our application needs to enable the SplitCompat Library for the app and each entry point (Activities or Fragments) in the downloaded Dynamic Feature module. There are some ways for enabling it, but in our case, we will use the default Application class:

And also enabling it in the Activity inside the Dynamic Feature module:

Our Main Activity will have a very simple layout with just two buttons. One for downloading the Dynamic Feature and a disabled button that will be enabled as soon as the new dynamic feature is installed.

Main Activity layout

First of all, we will get an instance of SplitInstallManager to be able to install the new module. In our example we will do it lazily:

In the first button, we will implement the SplitInstallRequest to build a request to download our Dynamic Feature and start the installation:

We will also add listeners to show visual information about the installation:

In the second button, we will set its enabled state based on the Dynamic Feature installation status:

This will enable the button when our Dynamic Feature has been installed and it is ready to launch. Since the Application module does not depend on the Dynamic module, it is not possible to access the Activity directly. There are several ways to access this module, but to keep it simple, we will use the good ol’ reflection:

Your application is now ready to be published! After downloading it, you will be able to install the Dynamic Feature on your own app. The full Activity implementation can be found here.

Unfortunately, if you simply run your app thought Android Studio, it will not work because it needs a connection with Google Play. This is a problem because you would need to upload your application to Google Play every time you do a single change. That’s why Google released Internal App Sharing.

Using Internal App Sharing

The internal app sharing allows developers to quickly share apps faster and without all the restrictions imposed by the Google Play Console. For sharing, all you need to do is log in with your developer account on the Internal App Sharing page and upload the apps. The only restriction here is that you can only upload apps that you own, meaning the application must be already published on Google Play.

Internal App Sharing page

After uploading the application, a link will be available to download it through the Google Play app. Before you use this link, there is one last step to be taken. Did you know that Google Play app has a developer mode?

Enabling Instant App sharing support on Google Play app

If you are familiar with Android development, you probably imagine how to enable the developer mode on Google Play app:

Open Google Play App > Settings > Click multiple time on Play Store version

After enabling the developer mode, a new option Internal App Sharing is shown in the option. Turn this feature on to allow installation of apps shared using this tool.

The classic clicks in the version code

Now you can use the link generated in the Internal App Sharing page to download the app on your device.

UX best practices

It is important to notice that the Google Play dialog informing that a new feature will be downloaded and requesting the user permission is only shown when the Dynamic Feature module is bigger than 10MB. If your Dynamic Feature does not exceed it, your app is not required to request any confirmation or show any progression for the user (although it is encouraged). For more information about best practices for demand delivery UX, please visit:

Frequently Asked Questions

Once the Dynamic Delivery is a relatively new tool in Android development, solutions for some issues are not easily found on the internet. Below are some common issues that I faced while I was working on Alkaa and how I solved them.

Q: When I try to run my Instrumented Tests the build fails with the following warning:

AAPT: error: resource bool/enable_system_alarm_service_default (aka com.package.feature.test:bool/enable_system_alarm_service_default) not found.

A: A library (WorkManager in the logs above) is requiring some value that is found in the merged manifest from the test variant. To fix it, you need to add the test dependency in the Dynamic Feature build.gradle :

dependencies {

implementation project(":app")

androidTestImplementation project(":app")

}

Q: How can I determine the module name to be downloaded by SplitInstallRequest.addModule ? Is the name on dist:title on AndroidManifest ?

A: No, the dist:title is not the dynamic feature module name. This is the title that the user may see (for example, if your module is bigger than 10MB). That’s why this one can (and should) be localized. The identifier name of the module is actually dist:split_name , which is automatically generated by Android Studio based on the module name. For more information, please refer to the official docs.

Q: Do I need to upload the AAB to Internal App Sharing for testing every single change on my Dynamic Feature Module?

A: No, you don’t. Uploading the AAB on Internal App Sharing is more related for testing the download flow. If you want to test something specific to that module, you can install the app through Android Studio with the Dynamic Feature Module included.

To do so, go to Edit Configurations... and check the Dynamic Feature Modules that you want to deploy. After that, you simply press play and the module will be available right away.

Checking “ondemand” module to be include

Conclusion

The Dynamic Delivery serving model allows a more flexible development and the possibility to include modules dynamically based on user’s device configuration and needs. The Dynamic Feature Module makes it possible to include only the modules that the user really uses, allowing smaller and optimized apps.

Please, refer to my personal projects for more information and code details. The first one is the project developed for this article and the second one is Alkaa, which have a Dynamic Feature Module on features/tracker .

I hope that this extended article helps you creating your first Dynamic Feature Module and clear up some common questions. Thanks a lot for reading it and if you have any question, please let me know!

Useful links