A Modular Android App and Dynamic Delivery

Kayvan Kaseb
Software Development
10 min readApr 3, 2020
A Modular Android App and Dynamic Delivery

Building a modular Android app plays an essential role in providing a clean and organised structures of apps particularly large size ones. Recently, after introducing app bundles and dynamic delivery concepts by Google, the size of the application package files are considerably reduced when a user downloads and installs an app on an Android device. Besides, another key benefit of dynamic delivery is the ability to split an app into multiple dynamic feature modules that can be installed on-demand. This essay aims to consider modularization and dynamic delivery approaches in Android app development.

Overview

In fact, modular programming is considered as a software design technique to separate functionalities into independent and interchangeable modules. As a result, each module includes everything necessary to execute a specific functionality as an objective. Modular programming is closely related to structured programming and object-oriented programming, all having the same target of facilitating construction of large software scales by decomposition into smaller pieces and all originating around the 1960s. In short, “modular programming” now refers to high-level decomposition of the code of an entire program into pieces. There are a number of advantages for using this technique in Android app development. Some benefits are mentioned as below:

Faster build time

Fundamentally, Gradle usually have two approaches to speed up compilation: First, using cache technique before the compilation. Second, do tasks in parallel as much as possible. As it clear, these approaches could not be efficient for an app because all codes need to be recompiled and reconsidered in a subsequent state for changing a line of code. However, by using multiple modules, Gradle can build several modules in parallel, and it can avoid build modules that there are no code changed. This leads to speed up your build time, and make it easier for modularized app in comparison with monolithic app.

Enhancing refactoring

Monolithic apps are usually difficult to change or improve because refactoring code in one place can easily cause some unforeseen side effects in somewhere else. However, In spit of the fact that refactoring could be still challenging even in a fully modularized app, refactoring can be done with minimizing the risks due to restriction in relationships among modules.

Improving the development process

On of the main problems in working on a large scale software with many developers is modifying and merging the codes simultaneously because of some conflicts that become appeared. If you split your app in a smart way, you can avoid concurrent modifications, or at least reducing those problems to a smaller set of modules. Besides, you can outsource the development of special features as modules to an external company. So, you can maintain the quality of your codes in an acceptable level during the app development process, and you can be able to diminish this process time as well.

Simplifying the test and continuous integration

Basically, in an modular app architecture, tests are written as small, function-based (feature-based) tests and then placed in execution order within the test suite. Each function-specific test provides full application test coverage for use in regression testing as well as feature (functional) testing; this constructs a clean and effective base for automated test development. Also, it is possible to run your continuous integration service faster by having small modules, which have larger modules depending on them. For instance, if you need to test a module; you will only need to run the modules that depend on it. As a result, the other modules are not impacted.

Enabling dynamic delivery

Basically, building an modular app’ features as dynamic feature modules is a key factor to take advantage of Dynamic Delivery options in Android development such as on demand, conditional, and instant delivery. Creating on demand dynamic features needs more effort and possible refactoring of your app codes. Thus, consider carefully which of your app’s features could benefit the most from being modularized into dynamic features and also benefiting from custom delivery options.

Reducing the size of APKs

Studies show that the size of APK can be an effective factor for installing and using your Android apps. This means from the Play Store statistics, it has been proved that some users drop between the moment they install the app, and the moment they can start using the app because of APK size. To prevent this issue, you can modularize your application with app bundle in order to reduce the installation size. Google mentioned the APKs generated from your app bundle are 64.3% smaller in comparison to universal APK.

An Overview on Dynamic Feature Modules

The main goals of dynamic delivery are to diminish the amount of time and bandwidth it takes to install an app from the Google Play Store, while also ensuring that only the minimum storage space is used by the app once it is installed. Dynamic feature modules (as on-demand modules) allow the various features, which create an Android app to be packaged into separate modules that are only downloaded and installed onto the device when they are required by the user. For instance, an app include news and discussion features. This app might only install the news feature by default, and separate the discussion feature into a dynamic feature module. It means when a user attempts to access the discussion feature, the app will download the feature module from the Play Store and launch it. If the user never accesses the discussion feature, the module will never be installed. As a result, you can make sure that the minimum amount of storage is used by the app. Initially, an app that utilizes dynamic feature modules has full access over how and when modules are installed. Additionally, the app could manage the frequency of features that are accessed by a user, and temporarily remove any infrequently used as well.

In addition to this section, a dynamic feature could be implemented as being an “instant” module. This replaces the Instant App concept of earlier Android releases and allows a dynamic feature module to be run on a device without having to install the app. This allows the app to appear with a “Try Now” button within the Google Play Store, or to be instantly launched on a device by clicking on a web URL

Dynamic Feature Module Architecture

Dynamic features bring this philosophy to a logical conclusion by allowing an app to install only what the user needs, when the user needs it. Given the flexibility and power of this ability, the implementation of dynamic feature modules is relatively simple. In basic terms, dynamic feature modules are built using split APK files which allow multiple APK files to be brought together to form a single app.

As we learned in Android App Bundle, Google Play Store uses your app bundle to generate and serve optimized APKs for each user’s device configuration. Therefore; they download only the code and resources they need to run your app. For instance, a user should not get x86 libs if the device architecture is armeabi, and users should not get other resources like strings or drawables they are not using. In this situation, the app is still installed via a single APK file, although this is customized for the user’s device. In contrast, dynamic feature modules work by splitting an app into multiple APK files. In other words, while an app uses split APK files, just only the base module is installed in the first download. The base module acts as the entry point into the app via a launch-able activity, and contains the byte-code and resources for the base functionality of the app together with configuration and build resources that are required by the rest of the app. The base module manifest file, for example, contains a merger of the manifest files for any dynamic feature modules bundled with the app. Furthermore, the version number for all of the dynamic feature modules are dictated by the version code setting in the build configuration file of the base module. The base module also contains a list of the dynamic feature modules included in the app bundle and all dynamic feature modules must list the base module as a dependency in their build configurations. Each dynamic feature takes the from of a module containing the byte-code, manifest, resources and build configuration together with any other assets like images or data files for that specific feature.

Additionally, you can be able to convert your independent modules into dynamic feature modules that can be downloaded later. By using dynamic delivery, users can download and install app’s dynamic features on demand after having already installed the base APK of your app. Thus, the downloadable size of your app decreases, and users do not have to install unused code or feature on their devices.

Dependency tree for an app served using split APKs from Google Dynamic Delivery Tutorial

To sum up, Split APKs are similar to regular APKs. This means they consists of compiled DEX byte-code, resources, and an Android manifest, but the Android platform is able to treat multiple installed split APKs as a single app. Dynamic Delivery with different types of split APKs can be indicated as follows:

  • Base APK: APKs includes the common code and resources that provides the basic functionality for your app.
  • Configuration APKs: APKs include native libraries and resources for a specific screen density, CPU architecture, or language.
  • Dynamic feature APKs: APKs contain code and resources that are not required when your app is first installed, but may be downloaded and installed later.

Creating a dynamic feature module

As it is mentioned before, dynamic feature modules are organized like regular app modules. They provide their own codes, resources, and assets in the directories you would expect. To utilize a dynamic feature module in your project, you should use Android Studio (3.2 Canary 14+). Also, Before creating a dynamic module, you have to create your app bundle. Some steps for creating a dynamic feature module can be mentioned as below:

  1. Select File > New > New Module from the menu bar. Then, in the Create New Module dialog, choose Dynamic Feature Module and click Next.
  2. On the Configure your new module screen, specify your module name.
  3. On the Configure your new module screen, specify the module title:
  • Check the Enable on-demand box if you want the module to be available for on demand downloads.
  • Check the Fusing box if you want this module to be available to devices running Android 4.4 (API level 20) and lower, include it in multi-APKs.

4. Click Finish and wait for the project to sync.

Dynamic Feature Module’s Android-manifest file

  • The first step is to declare your module as a new split APK of your application. You need to provide the split tag in the manifest’s root tag: split=”custom_dynamic_feature”
  • <dist:module/>tag: you can set up your feature module’s title and other configurations. This tag will be used by Google Play Store to identify the modules in your application.
  • dist:onDemand="true/false" : You can define this attribute for a module that is only available to the user when the user requests from the application, and it will not be available during the first installation.
  • In fact, on demand modules and configuration splits are only available on Lollipop+ devices. So, To make your dynamic feature available to earlier versions of Android, make sure to enable Fusing when you create a dynamic feature module.
  • <dist:module : This new XML element defines attributes that displays how the module is packaged and distributed as APKs.
  • dist:title="@string/feature_name" : Specifies a user-facing title for the module.
  • <dist:fusing include="true|false" /> : if you want this module to be available to devices running Android 4.4 (API level 20) and lower, include it in multi-APKs.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.test.dynamic"
split="dynamic-feature-test">

<dist:module
dist:onDemand="true"
dist:title="@string/title_test">
<dist:fusing include="true" />
</dist:module>

</manifest>

Dynamic feature module : build.gradle

First of all, Android use the new plugin that is called 'com.android.dynamic-feature' to build the dynamic feature module. Second, we need to specify the base application’s module name in dependencies block. Now, we can access the functionality of the base application’s module.

apply plugin: 'com.android.dynamic-feature'android {
//...
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':app')
}

Base module: build.gradle

You must declare your all dynamic feature modules in the base application’s build.gradle file in android part. This informs the Gradle that you need all your resources and codes, which are available to the other dynamic modules.

In addition to this section, other configurations can be added and indicated as follows:

  1. Signing configurations: App bundles are signed using signing configurations of the base module.

2. The minifyEnabled property: You can be able to enable code shrinking for your entire app project from just only the base module’s configuration.

3. versionCode and versionName: Gradle uses app version information that the base module provides.

Options for modularize our Android application

As a matter of fact, we have two options to modularize our application. One of them is based on features, and the another one uses a layer modularization. These two options have different advantages. In other words, feature modularization provides you encapsulation, and the possibility of on-demand delivery as well. To choose a feature among others in your app for that purpose, two key factors could be helpful: First, a small fraction of your users use that feature Second, that feature takes the significant amount of space in your application. On the other part, layer modularization provides you isolation, and allows you to isolate your third-party dependencies or the layers in your app, and also build a structure to your app. Actually, you can use both of them together; however, if you have a monolithic application for your app, you should use layer modularization first. Then, add the feature modularization after growing your structure appropriately.

In conclusion, building a modular Android app plays a significant role in providing a clean and organised structures for apps particularly large size ones. In recent years, after introducing app bundles and dynamic delivery concepts by Google, the size of the application package files are considerably reduced when a user downloads and installs an app on an Android device. This essay discussed modularization and dynamic delivery approaches in Android app development for having advanced architecture and structure based on Google documents.

--

--

Kayvan Kaseb
Software Development

Senior Android Developer, Technical Writer, Researcher, Artist, Founder of PURE SOFTWARE YAZILIM LİMİTED ŞİRKETİ https://www.linkedin.com/in/kayvan-kaseb