How we did it — Modularising an Android App — Part 2

Navigation between modules

Rachit M
2 min readApr 24, 2020

In the first part of this post, we talked about the testing plans, modularization structure and release plans.

In this post, we will share how we solved the navigation problems and reducing the inter-module dependency for navigation.

Navigating between modules

If all our activities are part of a single app module, starting a new activity is as simple as

startActivity(this, A::class)

Although we do end up increasing the coupling by referring to the class A and this happens across our projects.

For starting a new screen from a different module we had 2 approaches,

  1. Each feature module specifies it’s own navigator interface using which other features modules can start the activities of a different module.
  2. Another approach would be using Intent actions and firing them
  3. The one we chose was using Android app links and why it works better for us is what will share ahead.

We agreed on the app link url as app://myapp/feature1?key=value&key=value

The deep link values are part of the base build file.

resValue 'string', 'app_link_scheme', "app"
resValue 'string', 'app_link_host', "partner"

This makes sure we have a single source of truth for all the app link urls, and they urls are available to all the other feature modules through the base module.

And using Kotlin extension properties they are accessible to each activity as

val Context.baseAppLinkUrl: String
get() {
val appScheme = getString(R.string.app_link_scheme)
val appHost = getString(R.string.app_link_host)
return "$appScheme://$appHost"
}

Then inside any feature module manifest file we can easily add the deep link intent filter as

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="@string/app_link_host"
android:pathPrefix="/login"
android:scheme="@string/app_link_scheme" />
</intent-filter>

So this activity can be easily started from any other module/activity using a simple url as

val nextIntent = Intent(Intent.ACTION_VIEW, Uri.parse(app://myapp/login)
startActivity(nextIntent)

and no module/class dependency would be required.

We also added a helper ApplinkManagerto our base module, which would help us isolate the creation of Intent based on deep-link urls while also making sure that the user was logged.

The ApplinkManager can also be used to simplify notification deeplinks and reduce coupling.

We will talk more about sharing data between modules in the next and final post of this series Data Sharing between modules.

Thank you for reading along.

--

--