Home Android & Kotlin Books Android App Distribution

8
Adding Features Dynamically Written by Evana Margain Puig

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

With AABs, or Android App Bundles, Android lets you deliver features dynamically. In this context, dynamically means several possibilities. For instance, users can download only the parts of the app they need, or you can prompt them to download specific information if they access a specific part of your app.

Besides delivering features dynamically through your AAB, you can use another technique, called Feature Flagging. This term refers to conditional statements, controlled either by the server or the code itself, which tell the app whether to show or hide specific features.

What are dynamic features?

You’ll start this chapter by learning how to deliver features through a tool called Play Feature Delivery. This term refers to the features you can deliver after the user downloads the app on a per-need basis or any criteria you or your team determine.

Why are dynamic features useful?

There are many reasons why you might want to deliver features dynamically. Take a moment to explore some examples:

Dynamic feature options

Android provides four delivery options:

Feature flagging

Feature flagging isn’t an Android-specific term. It’s used in various applications and is more of a software development principle. Feature flagging gives you a way to enable or disable individual modules of your app depending on certain conditions. In this chapter, you’ll learn about this powerful tool.

Delivering dynamic modules

With basic definitions out of the way, it’s time to start really learning! In this section, you’ll add a series of dynamic modules to Pod Play and explore different delivery options.

Install-time delivery

You’ll start by creating an install-time delivery feature. There are three main reasons to choose this approach:

Creating a new module

Open up the starter project. Then create your new module by clicking File ▸ New… ▸ New Module. The menu will look like this:

Understanding your module configuration

The information you previously selected in the dialogs will mostly be in the newly created module’s Android Manifest. Open the Android Manifest for this new module. It is located in nameOfYourModule ▸ manifests ▸ AndroidManifest.xml. The three lines you need to pay attention to are:

Adding a screen to your install-time delivery module

Adding files to modules is a pretty straightforward process. It’s the same process that you use for your main module. You are going to add a screen to see how it works.

<item
    android:id="@+id/install_time_delivery_button"
    android:title="@string/install_time_delivery"
    android:icon="@android:drawable/ic_menu_preferences"
    app:showAsAction="collapseActionView|ifRoom"/>
val SETTINGS_CLASS_NAME = "com.example.installtimedeliveryexample.SettingsActivity"
val TAG_ACTIVITY = "PodcastActivity"

var settingsMenuItem = menu.findItem(R.id.install_time_delivery_button)

try {
  Class.forName(SETTINGS_CLASS_NAME)
  isInstallTimeModuleAvailable = true
  settingsMenuItem.isVisible = true
} catch (e: Exception) {
  settingsMenuItem.isVisible = false
  isInstallTimeModuleAvailable = false
  Log.d(TAG_ACTIVITY, "Couldn't start SettingsActivity, the class doesn't exist")
}

if (isInstallTimeModuleAvailable) {
  settingsMenuItem.setOnMenuItemClickListener {
    val intent = Intent().setClassName(this, SETTINGS_CLASS_NAME)
    startActivity(intent)
    true
  }
}

Testing your app with and without the modules

You will want to ensure your app works with or without some of your modules in certain cases. For example, maybe you want to disable a module for your users but want to be sure it doesn’t break the app. To configure this, go to Run ▸ Edit Configurations… in the top menu:

compileOptions {
  sourceCompatibility JavaVersion.VERSION_1_8
  targetCompatibility JavaVersion.VERSION_1_8
}

On-demand delivery

Creating an on-demand module is similar to creating an install-time module. You will go through the same steps you followed for install-time, but with some tweaks.

Play feature delivery

Google provides Play Feature Delivery, an API for getting on-demand modules. This API is available for Kotlin, Java, Android NDK and Unity. For this example, you’ll focus on Kotlin.

implementation "com.google.android.play:core:$google_play_core_version"
implementation "com.google.android.play:core-ktx:$google_play_core_ktx"

Split install manager

To get the on-demand module, you need to tie it to a button, or any other part of your app, to download it. There are no limitations on where you can trigger this download.

Adding a button to trigger the on-demand download

Now, you’ll add a button in the top menu bar on the home screen, next to the search icon. Navigate to menu_search.xml, which you can find in the main app module ▸ res ▸ menu. Switch to the editor’s code view and add the following lines before the </menu> closing tag:

<item android:id="@+id/download_on_demand_module_item"
 android:title="@string/download"
 android:icon="@android:drawable/stat_sys_download"
 app:showAsAction="always"/>

downloadMenuItem = menu.findItem(R.id.download_on_demand_module_item)

downloadMenuItem.setOnMenuItemClickListener {
 downloadModule()
}
private fun downloadModule(): Boolean {
  // 1
  val splitInstallManager = SplitInstallManagerFactory.create(applicationContext)

  //2
  val request = SplitInstallRequest
    .newBuilder()
    .addModule("onDemandDeliveryExample")
    .build()

  //3
  splitInstallManager
    .startInstall(request)
    .addOnSuccessListener { sessionId ->
      Toast.makeText(
        applicationContext,
        "Module installed successfully with sessionId $sessionId",
        Toast.LENGTH_LONG
      ).show()
    }
    .addOnFailureListener { exception ->
      Toast.makeText(
        applicationContext,
        "Module not installed with exception $exception",
        Toast.LENGTH_LONG
      ).show()
    }

   return true
}
import android.widget.Toast
import com.google.android.play.core.splitinstall.SplitInstallManagerFactory
import com.google.android.play.core.splitinstall.SplitInstallRequest

dependencies {
    implementation project(":app")
}

Conditional delivery

Now, let’s take a look at the third type of dynamic module, conditional delivery modules. These modules are only delivered when the device has specific capabilities.

Conditional delivery by country

You can also download individual modules depending on the user’s country. This is another option for conditional delivery that isn’t available from the New Module assistant.

<dist:user-countries dist:exclude="true">
  <dist:country dist:code="US" />
</dist:user-countries>

Checking whether the conditional module was downloaded

Just as you did in the previous examples, you will add a button in the navigation bar that will show a toast telling you whether the module was installed or not.

<item android:id="@+id/download_country_restricted_module"
  android:title="@string/download"
  android:icon="@android:drawable/btn_star"
  app:showAsAction="always"/>
 private lateinit var downloadConditionalModule: MenuItem
downloadConditionalModule = menu.findItem(R.id.download_country_restricted_module)

downloadConditionalModule.setOnMenuItemClickListener {
 downloadConditionalModule()
}
private fun downloadConditionalModule(): Boolean {
  // 1
  val splitInstallManager = SplitInstallManagerFactory.create(applicationContext)

  //2
  val request = SplitInstallRequest
    .newBuilder()
    .addModule("conditionalDeliveryExample")
    .build()

  //3
  splitInstallManager
    .startInstall(request)
    .addOnSuccessListener { sessionId ->
      Toast.makeText(
        applicationContext,
        "Conditional Module installed successfully with sessionId $sessionId",
        Toast.LENGTH_LONG
      ).show()
    }
    .addOnFailureListener { exception ->
      Toast.makeText(
        applicationContext,
        "Conditional Module not installed with exception $exception, you don't match the conditions",
        Toast.LENGTH_LONG
      ).show()
    }

   return true
}

Instant delivery

Instant delivery is the last option for dynamic features. It’s interesting and has gained a lot of traction, especially in mobile games. With instant delivery, you can let the user test a feature from your app without downloading it. Instant delivery is an excellent tool for showing users the best part of your app and potentially engaging new users.

Creating an instant module

As you did in your previous examples, go to File ▸ New ▸ New Module…. This time, instead of selecting Dynamic Feature Module, choose Instant Dynamic Feature Module. As the name explains, this option is for instant apps.

Feature flagging

Besides AABs’ capabilities, Feature flagging is a software development term that’s been around for a long time. Feature flagging refers to enabling or disabling features depending on a specific condition. Ideally, a server would control the flags to enable or disable them depending on the app’s needs.

<item android:id="@+id/write_notes_item"
 android:title="@string/notes"
 android:icon="@android:drawable/ic_menu_edit"
 app:showAsAction="always"/>

notesMenuItem = menu.findItem(R.id.write_notes_item)

visibilityOfNotesFeature()
private fun visibilityOfNotesFeature(): Boolean {
 notesMenuItem.isVisible = areNotesEnabled
 return true
}
 private var areNotesEnabled = true

Why would you want to implement a feature flag?

There are several reasons for implementing a feature flag. Some examples include:

Key points

  • Android App Bundles provide dynamic delivery options to make your app lighter and better meet your users’ needs.
  • You can create install-time delivery modules that are added to the app immediately when the user downloads your app.
  • Users can request on-demand delivery modules, depending on their needs.
  • Another option is conditional delivery modules, which will download depending on various factors like hardware requirements, version of the device or country.
  • Instant apps are an excellent option for engaging your users, but you have to ensure your base module and instant app module are not larger than 10MB.
  • Feature flagging is a technique used in Software Development for controlling the visibility of features and the functionality of your app. Ideally, the back end of your app would change this data.

Where to go from here?

There’s a lot to discover about Dynamic Features. For more on this topic check out Android App Bundles: Getting Started and Instant Apps: Getting Started, which will help you practice the skills you just learned.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

© 2022 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.