Skip to content

line-indonesia/android-on-demand-delivery-sample

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Android On Demand Delivery Sample App

This is sample repo for on demand delivery feature

Table of Contents:

  1. Pre-requisites
  2. Introduction
  3. Configure Instant Dynamic Feature Module
  4. Configure On Demand Dynamic Feature Module
  5. Download and Call Dynamic Feature from Base Module
  6. Setup Google Play Console for Instant App
  7. Screenshot
  8. Question and Answer
  9. Contributors

Pre-requisites

  • 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

Introduction

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:

  1. instantmodule (Instant Dynamic Feature Module)
  2. separatemoudle (On Demand Dynamic Feature Module)
  3. bigvideo (On Demand Dynamic Feature Module - Large size 30MB)

Configure Instant Dynamic Feature Module

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:

  1. The app maximum size (base app module and instant feature module) must be at most 10 MB
  2. No background services

To create instant module from Android Studio, follow this step:

  1. Select File > New > Module from Menu Bar.
  2. In the Create New Module dialog, select Instant Dynamic Feature Module and click Next.

  1. 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

Configure On Demand Dynamic Feature Module

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:

  1. Select File > New > Module from Menu Bar.
  2. In the Create New Module dialog, select Instant Dynamic Feature Module and click Next.

  1. Specify module name, package name, language, minimum SDK and click Next.

  1. 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

Download and Call Dynamic Feature from Base Module

Before you start adding activiy, asset, etc. You need to configure the Application and setup some base activity class:

  1. Create OnDemandApplication class and add it to AndroidManifest
class OnDemandApplication : Application() {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
        SplitCompat.install(this)
    }
}
<application
        android:name=".OnDemandApplication"
  1. 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)
    }
}
  1. 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>
  1. Extend the BaseSplitActivity to MainActivity
class MainActivity : BaseSplitActivity() {

}
  1. Create PageSeparateActivity inside your Dynamic Feature Module separatemodule.

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:

  1. Create SplitInstallManager
private lateinit var manager: SplitInstallManager
  1. Initialize manager in your onCreate method
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    manager = SplitInstallManagerFactory.create(this)
}
  1. Create button buttonOnDemandPageSeparate in activity_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" />
  1. Create separateModuleName and assign event to the button inside onCreate menthod
private val separateModuleName by lazy { getString(R.string.feature_name_separatemodule) }
binding.buttonOnDemandPageSeparate.setOnClickListener { loadAndLaunchModule(separateModuleName) }
  1. 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)
}
  1. 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)
        }
    }
}
  1. Register and unregister listener in onResume and onPause function
override fun onResume() {
    manager.registerListener(listener)
    super.onResume()
}

override fun onPause() {
    manager.unregisterListener(listener)
    super.onPause()
}
  1. 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

Setup Google Play Console for Instant App

To be able to upload the instant app in Google Play Console, follow this step:

  1. Select your app, then go to Setup > Advanced settings in Release Menu.
  2. Select Release Types tabulation.
  3. Click Add release type and Choose Google Play Instant.
  4. Then Google Play Instant will be added to Release Types option.

  1. Now when you are about to upload abb in Create New Release, there will be option to choose.
  2. Choose Standard to upload the Download App or choose Instant apps only for Instant App

Screenshot

  • Try Now button for Instant App

  • Instant App

  • Instant Module

  • Downloading Feature

  • On Demand Feature - Big Video

Question and Answer

Q: How to update Dynamic Feature module?

A: To update it, follow this step:

  1. Open build.gradle of the dynamic feature
  2. Update versionCode and/or versionName
defaultConfig {
    applicationId "com.linecorp.id.ondemanddelivery.feature.separatemodule"
    minSdkVersion 24
    targetSdkVersion 31
    versionCode 2
    versionName "1.0.1"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
  1. 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

Contributors

Releases

No releases published

Packages

No packages published

Languages