Navigation and Dynamic Features

In this tutorial, you’ll learn how to use an experimental version of Navigation Controller to navigate between dynamic feature modules. By Ivan Kušt.

Leave a rating/review
Download materials
Save for later
Share

At I/O 2018, Google introduced a new publishing format: Android App Bundles. These eliminate the need to publish multiple, large APK files for your app to run well on different devices. With App Bundles, each user gets an APK that’s tailor-made for their specific device.

App Bundles also offer dynamic delivery. This means you don’t have to install the whole app to use it, but divide the app into feature modules. At first, you just install the main module. You then install other modules only when needed.

In this tutorial, you’ll learn to use Dynamic Navigator libraries by refactoring Garden Planner, a single-module app, to use feature modules and dynamic navigation.

Your task is to separate the app into the following feature modules:

  • The existing app module.
  • An info feature module containing a screen with section details.
  • A notes feature module containing screens to add section and garden notes.

There’s also an awesome Jetpack Navigation Controller screencast, which quickly walks you through how to build a navigation graph.

For a start on App bundles check out our Getting Started With Android App Bundles tutorial.

Note: This tutorial assumes you know what Navigation Component and Android App Bundles are. For more information about Navigation component, check out our Navigation Architecture Component Tutorial.

There’s also an awesome Jetpack Navigation Controller screencast, which quickly walks you through how to build a navigation graph.

For a start on App bundles check out our Getting Started With Android App Bundles tutorial.

Getting Started

Start by using the Download Materials button at the top or bottom of this page to download everything you’ll need for this project.

Next, open the Garden Planner project in Android Studio 3.5 or later by selecting Open an existing Android Studio project from the Android Studio welcome screen:

Opening an existing project in Android Studio

Take a moment to get familiar with the app. Build and run and you’ll see the app’s main screen:

Garden Planner's main screen

The app is a simple garden planner that lets you plan out the layout of your garden. Tap on an empty tile and you’ll get a screen that lets you select what you’d like to plant there:

Options to plant in your garden

See the details or edit the selection by tapping on the section again:

Detail view of the Garden Planner

Tap on Info to get details about which plant you’ve set for a specific section:

Cabbage detail screen

Finally, you can add notes to either the section or the garden in general:

Adding notes

Before you start refactoring the app, take a deeper look at how the new features work.

Why Use Android App Bundles?

While Android App Bundles offer several advantages, they have one major disadvantage: Navigation between screens in modules is more complicated than with standard library modules. Here’s why.

When you use standard library modules, the main module can see them all. This makes using anything from the library modules simple:

Standard library module dependency layout

With feature modules, the dependencies are reversed. The modules have the main module as a dependent. Additionally, it’s possible that the user hasn’t installed a feature module yet. This makes navigating to screens implemented in feature modules tricky:

Feature module dependency layout

Until now, you had two approaches to use:

  1. Use reflection to access code in the feature module.
  2. Create a library module with interfaces for dynamic features that acts as a common dependency for base module and feature modules. You then load implementations at runtime with ServiceLoader.

Now, there’s a third, simpler option: Using a Dynamic Navigator library. This enables you to use Navigation Controller to navigate between destinations in feature modules.

Note: Google is actively developing the library, but it’s currently unstable. You shouldn’t use it in production until it reaches a stable release.

How Dynamic Delivery Works

The idea behind dynamic delivery is that the Play Store generates optimized APKs for each user’s device configuration. This has two benefits:

  • You upload only one archive on the Play Store, saving time.
  • Each user gets an optimized APK when they download the app, which makes the download size smaller.

How does it work? First, you upload the app in the new delivery format, Android App Bundle, which contains all the compiled code and resources for all configurations.

When users download your app, the Play Store uses dynamic delivery to generate optimized APK for their device.

Play Store delivering customized app downloads

How Feature Modules Work

Another benefit of dynamic delivery is that your app doesn’t have to install all at once. Instead, you break it down into pieces that install on demand.

This is possible thanks to a mechanism in Dynamic Delivery called split APK.

Note: Split APKs are available on Android 5.0 and higher.

Split APKs are similar to regular APKs, except they contain only a part of your app. Android is able to treat multiple split APKs as a single app. This enables you to break up your app into smaller chunks that download and install when required.

There are three types of split APKs:

  • Base APK: Contains code and resources for the app’s base functionality. Downloads when the user first downloads the app.
  • Configuration APKs: Hold native libraries and specific screen density, CPU architecture or language resources.
  • Dynamic feature APKs: Contain code and resources for a feature of your app from a single feature module. You can customize when and how the feature downloads using Play Core library.

How Navigation Component Works

Jetpack Navigation component consists of three key parts:

  • Navigation graph: An XML resource file that contains definitions for all navigation destinations in the app and their connections.
  • NavHost implementation: A container that displays destinations you define in navigation graph. Navigation component library provides default NavHostFragment implementation.
  • NavController: Manages navigation between destinations within NavHost.

When you navigate through your app, you tell NavController which destination you want to navigate to. NavController then displays the proper destination in the NavHost.

Note: for more information on Navigation Controller, check the official Android Developer documentation.

Navigation With Dynamic Feature Modules

Google’s Dynamic Navigator library extends the functionality of Navigation Component by enabling it to navigate to destinations from other feature modules. It does so by providing a new implementation of NavHost interface: DynamicNavHostFragment.

It’s time to add the library to the app!

Open the project-level build.gradle and add the maven block inside repositories so that the repository looks like:

allprojects {
  repositories {
    google()
    jcenter()
    maven {
      url "https://ci.android.com/builds/submitted/6043188/androidx_snapshot/latest/repository/"
    }
  }
}

This will add the snapshot repository to access the Dynamic Navigator library.

Finally, add the library dependency. Open build.gradle from the app module and add the following under dependencies:

  implementation "androidx.navigation:navigation-dynamic-features-fragment:2.3.0-SNAPSHOT"

Now, build and run to see if you get any errors.

Build and Run After Gradle Changes