Hey Android Devs, in this article we will see the implementation of navigation across multiple feature modules.
What is the Problem?
Recently, I was setting up a non-compose project in a multi-modular way. According to my use case, I was not convinced to go for Single Activity Architecture, instead, I was looking for something like at least one Activity per feature module, i.e; every feature module must have at least one activity as an entry point.
Jetpack navigation can work pretty well in a multi-modular approach. Still, it is mainly based on fragments. I feel that for big projects, there will be many instances where it would be better to have Activities instead of fragments because activities will have their own lifecycle and life will be much easier.
There are other ways as well for navigation purposes across modules but the main reason to choose the DeepLink approach is that it is platform-independent. In future, there might be cases when we launch some features and want our users to directly land to that particular feature module with just a tap on a link. Then it would be much easier and comparatively faster to scale.
- We will create one activity for each module as an entry point
- For each of the activities, we will create a processor which launches one particular activity after ensuring that the incoming deep link was supposed to be for that activity.
Enough talking, now let’s implement it
First of all, set up a non-compose project and create two feature modules called feature_01 and feature_02 and one core module besides the app module.
Module dependency can be defined as
app depends on all the modules core, feature_01 and feature_02
feature_01 depends on core
feature_02 depends on core
core depends on nothing
Here, the core is the common module for all the other modules.
Next, inside the core module, create a package for navigation which will contain some classes and interfaces which will be used to define deeplink processors for each of the feature modules.
First of all, create a DeeplinkProcessor interface. It will have two functions, one to match the deeplink and the other one to execute the launching of activity after matching.
Next, create a handler which will have only one function called process whose responsibility would be to execute the processor.
After this, we will create a DefaultHandler which will be an implementation of this DeeplinkHandler. It will call execute function for the first processor found matching the deeplink.
Now, we will create activities for each of the feature modules, namely Feature01Activity and Feature02Activity. Corresponding to them we will create DeeplinkProcessors for both of them as well, namely Feature01DeeplinkProcessor and Feature02DeeplinkProcessor.
For Feature02DeeplinkProcessor, we can handle some extra data as well coming along with the link.
Till here, we have all the building blocks to navigate from feature_01 to feature_02. Now we just have to combine all of this in action.
Now maintaining instances of all these processors can be tedious as we are going to have n number of modules in our application.
To help us in this we will use Dagger-Hilt to provide and execute all the processors defined across the modules.
In our app module, create an object called AppModule which will provide application context and a deeplink handler to handle all the defined processors.
In providesDefaultDeeplinkHandler() we need to provide a set of processors but since DeeplinkProcessor is an interface, we can’t just provide it by instantiation, that’s why we need to bind it using hilt only.
This will bind all the processors to the set required to create DefaultHandler.
Now we can inject this Default Handler inside our MainActivity and handle deeplinks.
Before moving to the actual navigation part we need to define the scheme and host for MainActivity in the manifest.xml file.
Now we can try navigation like this:
Here is a demo of navigation across modules.
Check out the sample repository here.
Let’s connect on LinkedIn and Twitter!