On this page
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
Step 1: Intent filter
<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>Step 2: Publish assetlinks.json
Host this at https://example.com/.well-known/assetlinks.json, served over HTTPS with Content-Type: application/json and no redirects:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.shop",
"sha256_cert_fingerprints": [
"AB:CD:...:EF"
]
}
}]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:
@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):
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
# 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.shopAndroid 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
onNewIntentand 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.
Walzi4K wallpapers for lock and home screenGet it โธ
NotiVaultNotification history: recover dismissed notificationsGet it โธ
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.