How to handle deeplinks using Jetpack Compose navigation
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
).
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").
Setup the deeplink in your route
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.
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