Yum News Yum News

Technology  ·  Artificial Intelligence  ·  Developer Insights

Breaking
Gemini Task Automation Guide: India UK Japan Apps ✦   How to Set Up ChatGPT Wallet for Agent Purchases ✦   How to Set Up and Use Gemini Live on Apple CarPlay ✦   How to Set Up Gemini Live on Apple CarPlay ✦   How to Use the Gemini Decisions API for Fast Choices ✦   How to Use Gemini Task Automation on Pixel Phones   ✦   Gemini 3.8 Live launches with native audio dialogue  ✦  Android September Drop adds Find Hub memory  ✦  ML Kit now supports Gemini Nano on-device inference
Navigation 3 Deep Link Setup Guide for Android Devs
androiddevelopertutorialshow-to

Navigation 3 Deep Link Setup Guide for Android Devs

Learn how to add Navigation 3 deep links on Android with DeepLinkRequest, DeepLinkMatcher, intent filters, and a synthetic back stack.

A notification, an email, or a shared product URL should open the right screen, not your home tab. Starting in Navigation 3 version 1.2.0, Android gives you typed APIs for that job: DeepLinkRequest models the incoming link, and DeepLinkMatcher maps it to a navigation key you can put on the back stack.

Android Developers documented the APIs on September 22, 2026, and announced them on September 30, 2026. This guide walks through the official flow: declare an intent filter, build matchers, match the incoming Intent, and restore a sensible back stack.

If you are also exposing app actions to on-device agents, pair this setup with AppFunctions for Android agents. Deep links and agent tools both start from a clear destination model.

What changed in Navigation 3 1.2.0

Navigation 3 already treats destinations as keys instead of a graph XML file. Version 1.2.0 adds deep linking on top of those keys. The runtime artifact is androidx.navigation3:navigation3-runtime.

A DeepLinkRequest holds a DeepLinkUri plus optional RequestExtras. Those extras can carry the intent action, a MIME type, or your own typed values. A DeepLinkMatcher accepts that request and returns a match result with a key, or null if it does not fit.

The library ships three built-in matchers:

  • StaticKeyDeepLinkMatcher for links that need no path arguments.
  • UriDeepLinkMatcher for hierarchical URI patterns such as www.example.com/users/{id}.
  • BackStackMatcher, usually applied with withBackStack, so a match can rebuild the screens the user would have seen on the way in.

You can still write a custom matcher when those three do not cover the case, such as a tel: link.

Android phone showing an app home screen on a desk

The system will not deliver a URL to your activity until the manifest says you want it. Add an <intent-filter> on the activity that owns navigation. For a web link, use ACTION_VIEW, the DEFAULT and BROWSABLE categories, and an https data element.

<activity android:name=".MainActivity" android:exported="true">
    <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:scheme="https"
            android:host="www.example.com"
            android:pathPrefix="/users" />
    </intent-filter>
</activity>

That filter covers https://www.example.com/users/42. Use pathPrefix when several destinations share a host path, and a full android:path when only one route should match. Android App Links add android:autoVerify="true" plus a Digital Asset Links file on your domain so the system can open your app without a disambiguation dialog. The Navigation 3 docs point to the standard intent-filter guide for that part. The matcher layer does not replace it.

Step 2: Model the request

Create a request from a string, a DeepLinkUri, or an Intent. The Intent constructor is the one you will use in production. It copies intent.data into the URI. If they are present, it also stores the action and MIME type in extras, and it saves non-null intent extras as a SavedState under DeepLinkRequest.IntentExtrasKey.

val request = DeepLinkRequest(intent = intent)
val uri = request.uri
val action = request.extras[DeepLinkRequest.ActionExtrasKey]

The official snippets also show helpers for MIME type extras and a requestExtras { } DSL when you need a custom key, such as a campaign id. Keep those keys typed by implementing RequestExtrasKey. Do not parse the raw URI string in the activity and then parse it again in the composable.

Step 3: Map URIs to navigation keys

Define one matcher per destination that should be linkable. StaticKeyDeepLinkMatcher is enough for a home screen that only needs an action filter. UriDeepLinkMatcher takes a pattern and a serializer for the destination key, then extracts path arguments into that key.

val homeMatcher = StaticKeyDeepLinkMatcher(
    HomeKey,
    listOf(DeepLinkMatcher.actionFilter(Intent.ACTION_VIEW))
)

val userProfileMatcher = UriDeepLinkMatcher(
    DeepLinkUri("www.example.com/users/{id}"),
    serializer<UserProfileKey>()
).withBackStack { matchResult ->
    listOf(HomeKey, matchResult.key)
}

withBackStack is the piece that keeps Up and Back honest. A deep link lands the user on one screen. Android’s navigation guidance says that path should still feel like the user walked there. Putting HomeKey under the profile key means Back returns to home instead of leaving the app immediately.

Collate matchers in one list. Different generic types need a star projection, which the official sample uses as List<DeepLinkMatcher<*, *>>. In a multi-module app you can collect them with multibindings instead of a hand-written list.

Developer writing Kotlin on a laptop

Step 4: Match the intent and build the back stack

Run this in onCreate, and again in onNewIntent if the activity uses singleTop or singleTask. A second link into an already running activity arrives through onNewIntent, not a fresh onCreate.

val request = DeepLinkRequest(intent = intent)
val matchResult = deepLinkMatchers
    .mapNotNull { it.match(request) }
    .maxOrNull()

val backStack: List<NavKey> = when (matchResult) {
    null -> listOf(HomeKey)
    is BackStackMatchResult<*, *> -> {
        @Suppress("UNCHECKED_CAST")
        matchResult.backStack as List<NavKey>
    }
    else -> listOf(matchResult.key as NavKey)
}

match runs every filter first, then matchRequest. MatchResult implements Comparable, so maxOrNull() picks the best hit when more than one matcher accepts the request. A null result should fall back to your start destination. A BackStackMatchResult already contains the synthetic stack. Any other result contributes a single key.

Pass that list into your NavDisplay back stack. Do not push the deep-link key on top of whatever the user already had open unless the product decision is to keep the old task. Cold start and warm start behave differently. Test both.

Install a debug build, then fire the same URI the filter claims to handle:

adb shell am start -a android.intent.action.VIEW \
  -d "https://www.example.com/users/42"

Confirm three things. The correct activity starts. The profile key is parsed with id 42. Back lands on home, not the launcher. Then send a second link while the app is in the foreground and confirm onNewIntent updates the stack. Android Developers’ deep-link series covers the older filter and App Links model. The matching step above is the Navigation 3-specific piece.

Keep the manifest host and the matcher pattern in sync. A filter for www.example.com and a matcher for example.com will open the app and then miss the destination.

Prefer HTTPS App Links for anything you share outside the app. Custom schemes still work for internal notifications, but other apps can claim the same scheme.

Put argument parsing in the serializer and the matcher, not in a composable LaunchedEffect. The back stack should already hold a valid key when the first frame draws.

If several matchers can hit the same URI, make the more specific pattern rank higher. Relying on list order alone is brittle once modules register matchers independently.

Handle the no-match case. A stale campaign link should open home, not crash on a missing path segment.

Conclusion

Navigation 3 1.2.0 splits deep linking into three jobs you can test on their own: the manifest filter, the request built from the Intent, and the matcher that returns a key or a synthetic back stack. Start with one HTTPS route, wire UriDeepLinkMatcher plus withBackStack, and prove it with adb before you add the rest of the site map.

Sources

Share this story