Universal Router


May 19, 2018
Jan 11, 2021
Esa Firman (esafirm)
Esa Firman (esafirm)
Irsal Shabirin (irsalshabirin)
Esa (esafirm-tiket)
Source code
APK file

Show card

Universal Router

Router for every ocassion ~

Universal router comes with two flavor, the core module which basically a link router that can convert your URI to whatever you need. And the Android module which more opinionated to how you can use it to help you solve your navigation problem


Add this to your project build.gradle

allprojects {
    repositories {
        maven { url "https://jitpack.io" }

And add this to your module build.gradle

dependencies {
    implementation "com.github.esafirm.universal-router:core:$routerVersion"
    implementation "com.github.esafirm.universal-router:android:$routerVersion"


It basically consist of two router

  1. SimpleRouter which route Any type of object to anything you need
  2. UrlRouter which takes URI instead of object

Some Examples

// Define router
class StringRouter : UrlRouter<String>() {

    init {
        addEntry("nolambda://test/{a}/{b}", "https://test/{a}/{b}") { _, param ->
            val first = param["a"]
            val second = param["b"]
            "$second came to the wrong neighborhood $first"

// Call router
// This will return string "you can to the wrong neighborhood yo"

For more sample, plese look at the samples directory.


Basically with just the core module you already can have a navigation system in your modular structured application (think dynamic module use case). The easiest way would be creating a Singleton router in your "core" module and then add entries in every other module, but this can get quite messy sometimes, this is when the android router module comes in.

First let's define our project structure:

├── app // Android app module, depends to all modules
├── cart // Feature cart, only depends to router
├── product // Feature product, only depends to router
└── approuter // Router libs that every module depends

In dynamic module use case the cart and product module would be depends the app module

Next what you want to create is the list of the routes in the "router" module, in this case approuter

object AppRouter {
    // Simplest form of Route
    object Home : Route()
    // Route support deeplink navigation
    object Cart : Route("https://bukatoko.com/cart")
    // Route also support navigation with parameter
    object Product : RouteWithParam<Product.ProductParam>(
        paths = arrayOf("https://bukatoko.com/{product_id}", "app://product/{id}"),
    ) {
        data class ProductParam(
            val productId: String

After that, you have to register your navigation logic to the Route

AppRouter.Cart.Register {
    context.startActivity(Intent(context, CartScreen::class.java))

If you want to initiate this in startup and your module doesn't have the access to Application class you can use the initializer

class CartRouterInitializer : RouterInitializer {
    override fun onInit(appContext: Context) {
        ... // do as above

Don't forget to register this on manifest


This is actually it if your navigation logic nature is "fire and forget", but in case you have to get something back (like Fragment) and use it in other place you can use the RouteProcessor<T>

// Processor only process return that has the same type as passed class
// In this case it will only process router that return Fragment
Router.addProcessor<Fragment> {
        .replace(R.id.container, it)

After that you can use the Router to navigate your app

// This will trigger Cart register lambda

// You can use the registered deeplink too

And that's it you got yourself a navigation system.

I can't stress enough that you should check samples for better understanding of the library

What's Next

  • Navigation type (push, replace, pop)
  • Annotation auto register (It's partially working now) �


MIT @ Esa Firman