โš™๏ธ Advanced Android Engineering and Emerging Technology

Deep Links, App Links, and Android App Actions

A link in an email, a QR code or a notification should open the exact screen in your app, not a browser. Deep links make that possible, and verified Android App Links make it seamless and secure. Here's how to set them up end to end.

โœ๏ธ Yunok Tech ๐Ÿ“… Updated โฑ 3 min read ๐ŸŽฏ Intermediate
On this page
  1. Deep links vs App Links
  2. Step 1: Intent filter
  3. Step 2: Publish assetlinks.json
  4. Step 3: Handle the link
  5. Step 4: Test
  6. Security
  7. Use cases
  8. Troubleshooting
  9. Frequently asked questions
  10. Conclusion

There are three kinds of links that can open your app: custom-scheme deep links (myapp://), unverified web links (which show a disambiguation dialog or open the browser), and verified Android App Links that open your app directly because you've proved you own the domain.

Deep links vs App Links

How Android resolves a link A user taps https://example.com/product/42. If the app has a verified App Link for example.com, Android opens the app directly. Otherwise the link opens in the browser or a chooser. Custom scheme links like myapp://product/42 only work if an app handles that scheme, and have no ownership verification. Tap linkhttps://example.com/p/42 Domain verifiedfor this app? Yes โ†’ open appdirectly No โ†’ browser(or chooser)
Since Android 12, unverified web links open in the browser by default.

Step 1: Intent filter

AndroidManifest.xmlXML
<activity android:name=".MainActivity" android:exported="true">
    <intent-filter android:autoVerify="true">
        <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" />
        <data android:host="example.com" />
        <data android:pathPrefix="/product/" />
    </intent-filter>
</activity>

Host this at https://example.com/.well-known/assetlinks.json, served over HTTPS with Content-Type: application/json and no redirects:

.well-known/assetlinks.jsonJSON
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.shop",
    "sha256_cert_fingerprints": [
      "AB:CD:...:EF"
    ]
  }
}]
Use the right fingerprint

With Play App Signing, use the app signing key fingerprint from Play Console (Setup โ†’ App signing), not only your upload key. Include your debug key's fingerprint separately if you want verification in debug builds.

Step 3: Handle the link

With Navigation Compose, declare deep links on destinations:

Navigation Compose deep linkKotlin
@Serializable data class Product(val id: String)

composable<Product>(
    deepLinks = listOf(navDeepLink<Product>(basePath = "https://example.com/product"))
) { entry ->
    val product = entry.toRoute<Product>()
    ProductScreen(product.id)
}

Or handle intents manually (for example with Navigation 3 or custom routing):

Manual parsingKotlin
fun parseDeepLink(uri: Uri?): AppRoute? {
    if (uri?.host != "example.com") return null
    val segments = uri.pathSegments
    return when {
        segments.size == 2 && segments[0] == "product" -> AppRoute.Product(segments[1])
        else -> null
    }
}
// Call from onCreate(intent) and onNewIntent(intent)

Step 4: Test

adb commandsShell
# Open a link
adb shell am start -a android.intent.action.VIEW \
  -c android.intent.category.BROWSABLE \
  -d "https://example.com/product/42"

# Check verification state
adb shell pm get-app-links com.example.shop

# Re-run verification after fixing assetlinks.json
adb shell pm verify-app-links --re-verify com.example.shop

Android Studio's App Links Assistant also helps generate and validate these files.

Security

  • Treat link parameters as untrusted input: validate IDs and never perform sensitive actions (payments, deletes) directly from a link without confirmation.
  • Require authentication before showing protected content.
  • Prefer verified App Links over custom schemes, which any app can claim.

Use cases

Marketing emails

Links open product pages in the app when installed, the website otherwise.

Notifications

Use the same routes for notification taps and links, so navigation logic is shared.

Password reset

Verified links route reset tokens safely into the app.

Troubleshooting

  • Verification fails: wrong fingerprint, a redirect on assetlinks.json, the wrong content type, or a host in the intent filter not covered by the file. Every host listed must verify.
  • Link opens browser in debug: the debug signing key isn't in assetlinks.json.
  • Screen opens twice: handle onNewIntent and set an appropriate launch mode.

Frequently asked questions

Are Firebase Dynamic Links still an option?

No. Firebase Dynamic Links has been shut down. Use App Links with your own domain, plus a web fallback.

Do I need a website?

For verified App Links, yes: you need a domain you control to host assetlinks.json.

Conclusion

Use verified App Links: add an intent filter with autoVerify, publish a correct assetlinks.json with the app signing fingerprint, route links through your navigation, test with adb, and validate parameters as untrusted input.

Next step: extend your app to the home screen with App Widgets and Shortcuts.

Official references

๐Ÿ“ฑ Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps โ†’

Ready to build real Android applications?

Architecture makes the most sense when you apply it to a real project and see why each boundary exists. Learn how maintainable Android applications are designed by building one.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp