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.gradle
of base module to establish a relationship
dynamicFeatures = [':feature:instantmodule']
AndroidManifest.xml
in 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.xml
in 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.gradle
of base module to establish a relationship
dynamicFeatures = [':feature:separatemodule']
AndroidManifest.xml
in 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
OnDemandApplication
class 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.xml
to 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
BaseSplitActivity
toMainActivity
class MainActivity : BaseSplitActivity() {
}
- Create
PageSeparateActivity
inside 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
manager
in youronCreate
method
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
manager = SplitInstallManagerFactory.create(this)
}
- Create button
buttonOnDemandPageSeparate
inactivity_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
separateModuleName
and assign event to the button insideonCreate
menthod
private val separateModuleName by lazy { getString(R.string.feature_name_separatemodule) }
binding.buttonOnDemandPageSeparate.setOnClickListener { loadAndLaunchModule(separateModuleName) }
- Create
loadAndLaunchModule
method
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
SplitInstallStateUpdatedListener
listener
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
onResume
andonPause
function
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
Release
Menu. - Select
Release Types
tabulation. - Click
Add release type
and ChooseGoogle Play Instant
. - Then
Google Play Instant
will be added toRelease Types
option.
- Now when you are about to upload abb in
Create New Release
, there will be option to choose. - Choose
Standard
to upload the Download App or chooseInstant apps only
for 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.gradle
of the dynamic feature - Update
versionCode
and/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