This is sample repo for on demand delivery feature
Table of Contents:
- Pre-requisites
- Introduction
- Configure Instant Dynamic Feature Module
- Configure On Demand Dynamic Feature Module
- Download and Call Dynamic Feature from Base Module
- Setup Google Play Console for Instant App
- Screenshot
- Question and Answer
- Contributors
- Android Studio 3.5 or higher
- Setup Google Play Core inside your
build.gradle
api "com.google.android.play:core:1.10.3"- Access to Play Console in order to test the on-demand features
This demo app will explain to you how to configure instant and on demand feature app
There's 3 feature module that are presented inside the app:
- instantmodule (Instant Dynamic Feature Module)
- separatemoudle (On Demand Dynamic Feature Module)
- bigvideo (On Demand Dynamic Feature Module - Large size 30MB)
With instant dynamic feature, user can try the app without needing to install APK(s) on their device. They can experience the app through the Try Now button on the Google Play Store.
There is some criteria which you need to satisfy to use it:
- The app maximum size (base app module and instant feature module) must be at most 10 MB
- No background services
To create instant module from Android Studio, follow this step:
- Select File > New > Module from Menu Bar.
- In the Create New Module dialog, select Instant Dynamic Feature Module and click Next.
- Specify module name, package name, language, minimum SDK, and module title. Then click Finish.
For Fusing, we will leave it as unchecked because we don't support pre-lollipop devices.
After that, android studio will automatically setup the instant module for your app
build.gradleof base module to establish a relationship
dynamicFeatures = [':feature:instantmodule']AndroidManifest.xmlin base module
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.linecorp.id.ondemanddelivery">
<dist:module dist:instant="true" />AndroidManifest.xmlin Instant Module
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.linecorp.id.ondemanddelivery.feature.instantmodule">
<dist:module
dist:instant="true"
dist:title="@string/title_instantmodule">
<dist:delivery>
<dist:install-time />
</dist:delivery>
<dist:fusing dist:include="false" />
</dist:module>For more detail information to configure Instant Delivery, you can read it at https://developer.android.com/guide/app-bundle/instant-delivery
With instant dynamic feature, user can download the base app at minimum size and later download and install those components on demand.
To create on demand module from Android Studio, follow this step:
- Select File > New > Module from Menu Bar.
- In the Create New Module dialog, select Instant Dynamic Feature Module and click Next.
- Specify module name, package name, language, minimum SDK and click Next.
- Specify module title and click Finish.
For Fusing, we will leave it as unchecked because we don't support pre-lollipop devices.
After that, Android Studio will automatically setup the on demand module for your app
build.gradleof base module to establish a relationship
dynamicFeatures = [':feature:separatemodule']AndroidManifest.xmlin On Demand Module
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.linecorp.id.ondemanddelivery.feature.separatemodule">
<dist:module
dist:instant="false"
dist:title="@string/title_separatemodule">
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="false" />
</dist:module>For more detail information to configure On Demand Delivery, you can read it at https://developer.android.com/guide/app-bundle/on-demand-delivery
Before you start adding activiy, asset, etc. You need to configure the Application and setup some base activity class:
- Create
OnDemandApplicationclass and add it toAndroidManifest
class OnDemandApplication : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
SplitCompat.install(this)
}
}<application
android:name=".OnDemandApplication"- Create
BaseSplitActivity(will use it later for base activity class)
abstract class BaseSplitActivity : AppCompatActivity() {
override fun attachBaseContext(ctx: Context?) {
super.attachBaseContext(ctx)
SplitCompat.install(this)
}
}- Create
feature_names.xmlto list all the module name that is available
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="feature_name_separatemodule">separatemodule</string>
</resources>- Extend the
BaseSplitActivitytoMainActivity
class MainActivity : BaseSplitActivity() {
}- Create
PageSeparateActivityinside your Dynamic Feature Moduleseparatemodule.
Note: When creating the dynamic feature activity, you need to extend it from BaseSplitActivity class.
class PageSeparateActivity : BaseSplitActivity() {
}After that the app is ready to download and call dynamic feature. Open your MainActivity and follow this step:
- Create
SplitInstallManager
private lateinit var manager: SplitInstallManager- Initialize
managerin youronCreatemethod
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
manager = SplitInstallManagerFactory.create(this)
}- Create button
buttonOnDemandPageSeparateinactivity_main.xml(this button will download and call dynamic feature)
<Button
android:id="@+id/buttonOnDemandPageSeparate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="16dp"
android:gravity="center"
android:text="On Demand Separate Page" />- Create
separateModuleNameand assign event to the button insideonCreatementhod
private val separateModuleName by lazy { getString(R.string.feature_name_separatemodule) }binding.buttonOnDemandPageSeparate.setOnClickListener { loadAndLaunchModule(separateModuleName) }- Create
loadAndLaunchModulemethod
private fun loadAndLaunchModule(name: String) {
//Check if module has been installed
if (manager.installedModules.contains(name)) {
launchActivityWithModuleName(name)
return
}
//Request install request
val request = SplitInstallRequest.newBuilder()
.addModule(name)
.build()
//Start download immediately
manager.startInstall(request)
}- Create
SplitInstallStateUpdatedListenerlistener
private val listener = SplitInstallStateUpdatedListener { state ->
val multiInstall = state.moduleNames().size > 1
val names = state.moduleNames().joinToString(" - ")
when (state.status()) {
SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> {
//In some cases, Google Play may require user confirmation before satisfying a download request. For example, if your app has not been installed by Google Play
manager.startConfirmationDialogForResult(state, this, CONFIRMATION_REQUEST_CODE)
}
SplitInstallSessionStatus.INSTALLED -> {
onSuccessfulLoad(names, launch = !multiInstall)
}
}
}- Register and unregister listener in
onResumeandonPausefunction
override fun onResume() {
manager.registerListener(listener)
super.onResume()
}
override fun onPause() {
manager.unregisterListener(listener)
super.onPause()
}- Launch activity upon success
private fun onSuccessfulLoad(moduleName: String, launch: Boolean) {
if (launch) {
if (manager.installedModules.contains(moduleName)) {
launchActivityWithModuleName(moduleName)
}
else {
Toast.makeText(this,
"This feature is only available in Downloaded App version. Please install the app from PlayStore.",
Toast.LENGTH_LONG
).show()
}
}
}
private fun launchActivityWithModuleName(moduleName: String) {
when (moduleName) {
instantModuleName -> launchActivity(INSTANT_FEATURE_CLASSNAME)
separateModuleName -> launchActivity(SEPARATE_FEATURE_CLASSNAME)
bigVideoName -> launchActivity(BIG_VIDEO_CLASSNAME)
}
}
private fun launchActivity(className: String) {
val intent = Intent().setClassName(BuildConfig.APPLICATION_ID, className)
startActivity(intent)
}To see all the detail and validation, you can open MainActivity
To be able to upload the instant app in Google Play Console, follow this step:
- Select your app, then go to Setup > Advanced settings in
ReleaseMenu. - Select
Release Typestabulation. - Click
Add release typeand ChooseGoogle Play Instant. - Then
Google Play Instantwill be added toRelease Typesoption.
- Now when you are about to upload abb in
Create New Release, there will be option to choose. - Choose
Standardto upload the Download App or chooseInstant apps onlyfor Instant App
- Try Now button for Instant App
- Instant App
- Instant Module
- Downloading Feature
- On Demand Feature - Big Video
Q: How to update Dynamic Feature module?
A: To update it, follow this step:
- Open
build.gradleof the dynamic feature - Update
versionCodeand/orversionName
defaultConfig {
applicationId "com.linecorp.id.ondemanddelivery.feature.separatemodule"
minSdkVersion 24
targetSdkVersion 31
versionCode 2
versionName "1.0.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}- You also need to update the app version to be able to upload it to PlayStore
defaultConfig {
applicationId "com.linecorp.id.ondemanddelivery"
minSdkVersion 24
targetSdkVersion 31
versionCode 4
versionName "1.1.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}- When app is updated, user will only update all the module they have installed (Base App size: 2.3MB)
- Updating app that has installed all dynamic feature (Downloading app size: 33.70MB)
=========================================
Q: How to implement Dynamic Feature module to app which has build variant?
A: The source code is now updated with build variant implementation to it.
When app has build variant, all dynamic feature module need to have the same build variant.
You can read more detail information in https://android.jlelse.eu/dynamic-feature-module-with-product-flavors-and-app-bundle-c246640eb64d
When building the app, make sure you set all the build variant of app and dynamic feature to be the same





