State of Compose 2023 results are in! Click here to learn more
Published on

How to handle deeplinks using Jetpack Compose navigation

Authors

In this tutorial you will learn how to handle deep links in your Jetpack Compose app using the Jetpack Compose Navigation library.

We will cover the cases where deeplink from an external app (such as clicking on a web link) and also from your own app (such as clicking on a Notification).

Featured in Android Weekly #562

๐Ÿ’ก

Learn how to use Jetpack Compose Navigation in this tutorial.

Include the Jetpack Compose Navigation dependency

Add the following dependency to your app/build.gradle file:

dependencies {
    def nav_version = "2.5.3"
    implementation "androidx.navigation:navigation-compose:$nav_version"
}

Setup your implicit Intent filter

Jetpack Compose Navigation can handle implicit intents for you. To do that you need two things. First include the respective IntentFilter in your AndroidManifest.xml file. Second, specify the respective deep link in the Compose side.

For this example, I will setup deeplinks to start my Android app once a user navigates to an article at composables.com/blog:

Include the Intent Filter in AndroidManifest.xml

The intent filter needs to match the implicit intent you would like to start the deep link:

<activity
    android:name=".MainActivity"
    ...
>
<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data
        android:host="composables.com"
        android:scheme="https" />
</intent-filter>
</activity>

Intents explained in 90 words

An Intent contains information about a user action. It contains an action (such as view, send, call) and details about the action (such as a phone number, an id, a url).

Intents is the way Android knows how to launch your favorite mail client when you want to send an email.

There are two kind of intents: explicit and implicit. Implicit intents are focused on actions ("I want to play music"). Explicit intents are focused on specific Android components to handle the Intent ("I want to play music on Spotify").

The way the Navigation library knows how to handle the deeplink for you is by passing the desired deepLinks into your route:

val navController = rememberNavController()

NavHost(navController, "home") {
    //... your other routes here

    composable(
        "details?article={argument}",
        deepLinks = listOf(navDeepLink {
            uriPattern = "https://composables.com/blog/{argument}"
        }),
    ) { backStackEntry ->
        val article = backStackEntry.arguments?.getString("argument")
        Text("Showing /$article")
    }
}

in the above sample we tell the Navigation Library to handle any deeplinks that can satisfy the given uri pattern.

at this stage you might be wondering what are all those question marks and brackets. Let's break this down:

"details?article={article}" : defines a route called details with the optional parameter of article. In our route, we can access this optional parameter as argument (keep reading: it will make more sense).

https://composables.com/blog/{argument} : the uri pattern we expect to be satisfied during deep linking. This expects the data of the intent to contain https://composables/blog/ plus an additional (optional) parameter. In this case it is the article that we defined in the route parameters.

Whenever our apps is triggered due to a deep link (such as clicking on https://composables.com/blog/navigation-tutorial on the browser), the <intent-filter> we set in the AndroidManifest.xml will cause the MainActivity to start. As we have set the uriPattern that can handle https://composables.com/blog/{article} the Navigation library will automatically navigate to the details route.

You may pass any kind of intent properties into the navDeepLink builder, such as actions and mimetype.

Note here that the Navigation Library will navigate to the best match deep link it can find in your Navigation graph. If no matches were found, then it will just navigate to the start destination.

Example: Deep linking from Notifications

It doesn't matter how our activity that hosts our graph is launched from. The Navigation library will navigate to the deep link we have set as long as the launching intent's parameters are satisfied.

The following code will display a Notification that will start the main activity and deep link into the details route:

val notificationId = "navigation-tutorial".hashCode()
val intent = Intent(
    Intent.ACTION_VIEW,
    Uri.parse("https://composables.com/blog/navigation-tutorial")
)
val activity = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)

notificationManager.notify(
    notificationId,
    NotificationCompat.Builder(context, "channel-id")
        .setContentTitle("๐Ÿงญ Navigation in Jetpack Compose")
        .setContentText("Everything you need to know")
        .setSmallIcon(R.drawable.ic_system_notification)
        .setContentIntent(activity)
        .build()
)

When the user clicks on the notification, our activity will be launched and the Navigation library will navigate to the details route and forward navigation-tutorial into the optional argument.

๐Ÿ’ก

The above sample assumes that you have already created a Notification channel with the id "channel-id".


Extra ๐ŸŽ: How to launch websites from the terminal

One of the simplest ways to try out your deeplinks you are developing is by using adb to launch the intent you want to deep link with:

adb shell am start -W -a android.intent.action.VIEW -d โ€œhttps://composables.com/blog/navigationโ€

this will fire an Intent with the action android.intent.action.VIEW and https://composables.com/blog/navigation as data.


In this tutorial you learnt how to handle deep links in Jetpack Compose. Your learnt how to setup your navigation graph so that it automatically navigate to the desired route when a deep link is triggered. We saw how to setup our route so that it is display when the user clicks on a website or a notification.


Recommended reading

How to navigate using Jetpack Compose Navigation with examples

How to model complex screens in Jetpack Compose