Smart Links — Android Setup Guide
---
sidebar_label: Smart Links — Android sidebar_category: Smart Links Integration
Smart Links — Android Setup Guide
This guide covers everything you need to do inside your Android app to support Linkzly Smart Links (called Deeplinks in the dashboard). When a user taps a Smart Link on Android, the goal is for your app to open directly to the correct screen. If the app is not installed, Linkzly redirects to the Google Play Store, and after the user installs and opens the app, Linkzly delivers the original deep link destination — this is called deferred deep linking.
What Linkzly does automatically:
- Hosts the Digital Asset Links file at
https://<your-domain>/.well-known/assetlinks.json - Handles deferred deep link storage and delivery
- Routes uninstalled users to the Google Play URL you configured
- Tracks clicks, installs, and deep link delivery events
What you must do in your Android project:
- Add your SHA-256 certificate fingerprint(s) to the Linkzly app registration
- Add an intent filter with
android:autoVerify="true"inAndroidManifest.xmlfor your Linkzly domain - Handle the incoming intent in your Activity and parse the URI to navigate to the correct screen
Prerequisites
Before starting the Android configuration, complete the app registration in the Linkzly console. The Android setup requires the following:
| Requirement | Where to Find It |
|---|---|
| Package Name | applicationId in your app-level build.gradle. Example: com.yourcompany.yourapp |
| SHA-256 Certificate Fingerprint | From your debug keystore, release keystore, or Google Play Console (see Step 1) |
| Linkzly domain | Linkzly Console → Apps → [Your App] → the hosted subdomain or your custom domain. Example: yourapp.linkz.ly |
| Smart Link (Deeplink) | At least one Smart Link created and in Active status in Linkzly Console → Deeplink |
If you have not yet registered your app in Linkzly, follow the steps in the Smart Links overview first — specifically Step 1 (Register an App) and Step 3 (Create a Deeplink). Come back here once you have your Linkzly domain and at least one Smart Link created.
Step 1 — Get Your SHA-256 Certificate Fingerprint
Android App Links require that your app's signing certificate fingerprint is listed in the assetlinks.json file that Linkzly serves. The fingerprint must match the certificate used to sign the APK installed on the device.
You will add this fingerprint to the Linkzly console so Linkzly can include it in the assetlinks.json file automatically.
Debug Keystore
For development builds signed with the default Android debug keystore:
keytool -list -v \
-keystore ~/.android/debug.keystore \
-alias androiddebugkey \
-storepass android \
-keypass android
Release Keystore
For production builds signed with your release keystore:
keytool -list -v \
-keystore /path/to/your-release.keystore \
-alias your-key-alias \
-storepass your-store-password
Both commands output a block containing:
Certificate fingerprints:
SHA1: AA:BB:CC:...
SHA256: AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99
Copy the SHA-256 value — the colon-separated 64-character hex string.
Google Play App Signing
If you use Google Play App Signing (the default for new apps), Google re-signs your APK with its own key after you upload it. The SHA-256 fingerprint you add to Linkzly must match Google's signing key, not your upload key — they are different.
- Open Google Play Console → Your App → Setup → App integrity.
- Under App signing key certificate, copy the SHA-256 certificate fingerprint shown there.
Important: If you use Google Play App Signing and add only your local keystore fingerprint, App Links verification will fail on production builds distributed through the Play Store. Always add the fingerprint from the Google Play Console for production.
You can add multiple fingerprints — for example, one for your debug keystore and one from the Google Play Console. Linkzly includes all registered fingerprints in the assetlinks.json file.
Step 2 — Add the Fingerprint to Linkzly
- Go to Linkzly Console → Apps.
- Click on your registered Android app.
- In the SHA-256 Fingerprints section, paste the fingerprint you copied in Step 1.
- Click Add Fingerprint. Repeat for each additional fingerprint (debug, release, Play signing key).
- Click Save.
Linkzly immediately updates the assetlinks.json file on your domain to include the new fingerprint.
Step 3 — Verify the assetlinks.json File
Linkzly hosts the Digital Asset Links file for you automatically. Verify it is reachable and contains the correct values by running this command in Terminal, replacing the domain with yours:
curl https://yourapp.linkz.ly/.well-known/assetlinks.json
The response will be a JSON array with a structure similar to:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourcompany.yourapp",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
]
}
}
]
Check that:
package_namematches your app's package name exactly (case-sensitive).sha256_cert_fingerprintscontains the fingerprint you added, including the colons.
If the file returns a 404 or an HTML error page, allow up to 5 minutes after saving your app registration in Linkzly and try again. For custom domains, verify your DNS CNAME record points to Linkzly's servers and has propagated.
Step 4 — Configure AndroidManifest.xml
Add an <intent-filter> with android:autoVerify="true" to the Activity that should handle your Smart Links. The autoVerify attribute instructs Android to verify App Link ownership at install time by fetching the assetlinks.json file from your domain.
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<!-- Default launcher intent filter — keep your existing entry point -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- App Links intent filter — handles Linkzly Smart Links -->
<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"
android:host="yourapp.linkz.ly" />
</intent-filter>
</activity>
Replace yourapp.linkz.ly with your Linkzly hosted subdomain or custom domain.
If you have Smart Links on more than one domain, add a separate <intent-filter> block for each domain:
<!-- If using a custom domain in addition to the hosted subdomain -->
<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"
android:host="go.yourcompany.com" />
</intent-filter>
Key points:
android:autoVerify="true"is required. Without it, Android shows a disambiguation dialog instead of opening your app directly.android:launchMode="singleTask"ensures the activity is not started twice if the app is already in the foreground when the link is tapped.android:exported="true"is required on Android 12 (API 31) and above for any activity with an intent filter.- Only add
https— Linkzly Smart Links always use HTTPS. You do not need anhttpvariant.
Step 5 — Handle the Incoming Intent in Your Activity
Override onCreate() and onNewIntent() in the activity you declared in the manifest. Both methods need to call your intent handler so the deep link is processed whether the app was already running or launched fresh.
Kotlin Activity with Intent Parsing
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Handle the App Link intent that launched this activity
handleDeepLinkIntent(intent)
}
// Called when the app is already running and receives a new App Link
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleDeepLinkIntent(intent)
}
private fun handleDeepLinkIntent(intent: Intent) {
if (intent.action != Intent.ACTION_VIEW) return
val uri: Uri = intent.data ?: return
// Extract the deep_link_path query param set in the Linkzly dashboard.
// Fall back to the raw URI path if the param is not present.
val deepLinkPath: String = uri.getQueryParameter("deep_link_path")
?: uri.path
?: "/"
// Collect any additional query parameters as supplementary data
val params: Map<String, String> = uri.queryParameterNames
.filter { it != "deep_link_path" }
.associateWith { name -> uri.getQueryParameter(name) ?: "" }
route(path = deepLinkPath, params = params)
}
private fun route(path: String, params: Map<String, String>) {
// Normalize the path and split into segments
val segments = path
.trimStart('/')
.split("/")
.filter { it.isNotEmpty() }
when (segments.firstOrNull()) {
"product" -> {
// deep_link_path = /product/456
val productId = segments.getOrElse(1) { "" }
openProductScreen(productId, params)
}
"promo" -> {
// deep_link_path = /promo/summer-sale
val slug = segments.getOrElse(1) { "" }
openPromoScreen(slug)
}
"profile" -> {
// deep_link_path = /profile/user123
val userId = segments.getOrElse(1) { "" }
openProfileScreen(userId)
}
"onboarding" -> {
// deep_link_path = /onboarding + data param: step=welcome
val step = params["step"] ?: "welcome"
openOnboardingScreen(step)
}
"article" -> {
// deep_link_path = /article/789
val articleId = segments.getOrElse(1) { "" }
openArticleScreen(articleId)
}
else -> openHomeScreen()
}
}
// --- Navigation helpers — replace with your actual navigation code ---
private fun openProductScreen(productId: String, params: Map<String, String>) {
val intent = Intent(this, ProductActivity::class.java).apply {
putExtra("product_id", productId)
putExtra("campaign", params["campaign"])
}
startActivity(intent)
}
private fun openPromoScreen(slug: String) {
val intent = Intent(this, PromoActivity::class.java).apply {
putExtra("promo_slug", slug)
}
startActivity(intent)
}
private fun openProfileScreen(userId: String) {
val intent = Intent(this, ProfileActivity::class.java).apply {
putExtra("user_id", userId)
}
startActivity(intent)
}
private fun openOnboardingScreen(step: String) {
val intent = Intent(this, OnboardingActivity::class.java).apply {
putExtra("start_step", step)
}
startActivity(intent)
}
private fun openArticleScreen(articleId: String) {
val intent = Intent(this, ArticleActivity::class.java).apply {
putExtra("article_id", articleId)
}
startActivity(intent)
}
private fun openHomeScreen() {
// Already on home — no navigation needed, or navigate to HomeActivity
}
}
Step 6 — Jetpack Compose Navigation
If your app uses Jetpack Compose with NavController, handle the incoming intent in your MainActivity and pass the deep link URI to the navigation host. The Compose Navigation library has built-in support for parsing deep links declared in your nav graph, but you can also extract parameters manually for full control.
Using Compose Navigation with Deep Link Declarations
Declare the deep link on each destination in your nav graph:
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import androidx.navigation.navDeepLink
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen()
}
composable(
route = "product/{productId}",
arguments = listOf(navArgument("productId") { type = NavType.StringType }),
deepLinks = listOf(navDeepLink {
uriPattern = "https://yourapp.linkz.ly/abc123?deep_link_path=/product/{productId}"
})
) { backStackEntry ->
val productId = backStackEntry.arguments?.getString("productId") ?: ""
ProductDetailScreen(productId = productId)
}
composable(
route = "promo/{slug}",
arguments = listOf(navArgument("slug") { type = NavType.StringType }),
deepLinks = listOf(navDeepLink {
uriPattern = "https://yourapp.linkz.ly/abc123?deep_link_path=/promo/{slug}"
})
) { backStackEntry ->
val slug = backStackEntry.arguments?.getString("slug") ?: ""
PromoScreen(slug = slug)
}
composable(
route = "profile/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType }),
deepLinks = listOf(navDeepLink {
uriPattern = "https://yourapp.linkz.ly/abc123?deep_link_path=/profile/{userId}"
})
) { backStackEntry ->
val userId = backStackEntry.arguments?.getString("userId") ?: ""
ProfileScreen(userId = userId)
}
}
}
Manual Compose Navigation via Intent Handling
For more control — particularly when Linkzly passes deep_link_path as a query parameter rather than a path segment — handle the intent manually in MainActivity and call navController.navigate() directly:
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.remember
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
class MainActivity : ComponentActivity() {
private var navController: NavHostController? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val controller = rememberNavController()
navController = controller
AppNavHost(navController = controller)
}
// Process the intent that launched the activity
handleDeepLinkIntent(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleDeepLinkIntent(intent)
}
private fun handleDeepLinkIntent(intent: Intent) {
if (intent.action != Intent.ACTION_VIEW) return
val uri: Uri = intent.data ?: return
val deepLinkPath = uri.getQueryParameter("deep_link_path") ?: uri.path ?: "/"
val params = uri.queryParameterNames
.filter { it != "deep_link_path" }
.associateWith { uri.getQueryParameter(it) ?: "" }
// Dispatch navigation after the Compose content is ready
navController?.let { controller ->
navigateFromPath(controller, deepLinkPath, params)
}
}
private fun navigateFromPath(
navController: NavHostController,
path: String,
params: Map<String, String>
) {
val segments = path.trimStart('/').split("/").filter { it.isNotEmpty() }
when (segments.firstOrNull()) {
"product" -> {
val productId = segments.getOrElse(1) { "" }
navController.navigate("product/$productId")
}
"promo" -> {
val slug = segments.getOrElse(1) { "" }
navController.navigate("promo/$slug")
}
"profile" -> {
val userId = segments.getOrElse(1) { "" }
navController.navigate("profile/$userId")
}
"onboarding" -> {
val step = params["step"] ?: "welcome"
navController.navigate("onboarding?step=$step")
}
else -> navController.navigate("home")
}
}
}
Step 7 — Deferred Deep Linking
When a user taps a Smart Link but does not have your app installed, Linkzly redirects them to the Google Play Store URL you configured. Linkzly handles the deferred deep link storage on its side.
After the user installs the app from the Play Store and opens it for the first time, Linkzly delivers the original deep link through the Play Install Referrer API. The referrer string contains the original Smart Link destination URL, which your app reads on first launch and uses to navigate the user to the correct screen.
Deferred Deep Link Handling with Play Install Referrer
Add the Play Install Referrer library to your app-level build.gradle:
dependencies {
implementation 'com.android.installreferrer:installreferrer:2.2'
}
Read the referrer on first launch in your MainActivity. Guard this behind a one-time flag stored in SharedPreferences so it only runs once — on the very first app open after install:
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerStateListener
import com.android.installreferrer.api.ReferrerDetails
class MainActivity : AppCompatActivity() {
private lateinit var referrerClient: InstallReferrerClient
companion object {
private const val PREFS_NAME = "linkzly_prefs"
private const val KEY_REFERRER_PROCESSED = "referrer_processed"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Handle a direct App Link intent first (takes priority)
if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
handleDeepLinkIntent(intent)
} else {
// Otherwise, check for a deferred deep link from the Play Install Referrer
checkDeferredDeepLink()
}
}
private fun checkDeferredDeepLink() {
val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
if (prefs.getBoolean(KEY_REFERRER_PROCESSED, false)) {
// Already processed referrer on a previous launch — skip
return
}
referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
if (responseCode == InstallReferrerClient.InstallReferrerResponse.OK) {
val details: ReferrerDetails = referrerClient.installReferrer
val referrerUrl = details.installReferrer
// Mark as processed so this only runs once
prefs.edit().putBoolean(KEY_REFERRER_PROCESSED, true).apply()
if (referrerUrl.isNotEmpty()) {
// Linkzly encodes the original destination in the referrer URL
handleDeferredDeepLink(referrerUrl)
}
}
referrerClient.endConnection()
}
override fun onInstallReferrerServiceDisconnected() {
// Connection to Play Services dropped — safe to ignore for deferred links
}
})
}
private fun handleDeferredDeepLink(referrerUrl: String) {
try {
val uri = Uri.parse(referrerUrl)
val deepLinkPath = uri.getQueryParameter("deep_link_path") ?: uri.path ?: return
val params = uri.queryParameterNames
.filter { it != "deep_link_path" }
.associateWith { uri.getQueryParameter(it) ?: "" }
runOnUiThread {
route(path = deepLinkPath, params = params)
}
} catch (e: Exception) {
// Referrer URL was not a valid Linkzly deep link — ignore
}
}
private fun handleDeepLinkIntent(intent: Intent) {
val uri: Uri = intent.data ?: return
val deepLinkPath = uri.getQueryParameter("deep_link_path") ?: uri.path ?: "/"
val params = uri.queryParameterNames
.filter { it != "deep_link_path" }
.associateWith { uri.getQueryParameter(it) ?: "" }
route(path = deepLinkPath, params = params)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
if (intent.action == Intent.ACTION_VIEW) {
handleDeepLinkIntent(intent)
}
}
private fun route(path: String, params: Map<String, String>) {
val segments = path.trimStart('/').split("/").filter { it.isNotEmpty() }
when (segments.firstOrNull()) {
"product" -> openProductScreen(segments.getOrElse(1) { "" }, params)
"promo" -> openPromoScreen(segments.getOrElse(1) { "" })
"profile" -> openProfileScreen(segments.getOrElse(1) { "" })
"onboarding" -> openOnboardingScreen(params["step"] ?: "welcome")
"article" -> openArticleScreen(segments.getOrElse(1) { "" })
else -> openHomeScreen()
}
}
// --- Navigation helpers ---
private fun openProductScreen(productId: String, params: Map<String, String>) { /* ... */ }
private fun openPromoScreen(slug: String) { /* ... */ }
private fun openProfileScreen(userId: String) { /* ... */ }
private fun openOnboardingScreen(step: String) { /* ... */ }
private fun openArticleScreen(articleId: String) { /* ... */ }
private fun openHomeScreen() { /* ... */ }
}
Requirement: For deferred deep linking to work, the Google Play URL field in your Linkzly app registration must contain a valid Play Store listing URL for your app. This is the URL Linkzly redirects uninstalled users to so they can install the app.
Testing
Simulate an App Link with ADB
Use adb to simulate tapping a Smart Link with the app installed:
adb shell am start \
-W \
-a android.intent.action.VIEW \
-d "https://yourapp.linkz.ly/abc123?deep_link_path=%2Fproduct%2F456&campaign=summer" \
com.yourcompany.yourapp
Replace the URL with one of your actual Smart Links from the Linkzly console, and replace com.yourcompany.yourapp with your package name. If the intent filter is configured correctly, Android opens your activity and handleDeepLinkIntent() is called.
Verify App Link Verification Status
After installing the app, check whether Android successfully verified the App Link association:
# <span id="trigger-re-verification-useful-after-updating-assetlinksjson"></span>Trigger re-verification (useful after updating assetlinks.json)
adb shell pm verify-app-links --re-verify com.yourcompany.yourapp
# <span id="wait-510-seconds-then-check-the-result"></span>Wait 5–10 seconds, then check the result
adb shell pm get-app-links com.yourcompany.yourapp
The output lists each declared domain and its verification status. A correctly configured setup shows:
com.yourcompany.yourapp:
ID: ...
Signatures: [...]
Domain verification state:
yourapp.linkz.ly: verified
If the status shows none, ask, or legacy_failure, see the Troubleshooting section below.
Test Deferred Deep Linking
You can simulate a deferred deep link install by passing a referrer value via ADB on a device:
# <span id="simulate-the-play-store-referrer-that-linkzly-would-set"></span>Simulate the Play Store referrer that Linkzly would set
adb shell am broadcast \
-a com.android.vending.INSTALL_REFERRER \
-n com.yourcompany.yourapp/.InstallReferrerReceiver \
--es "referrer" "https%3A%2F%2Fyourapp.linkz.ly%2Fabc123%3Fdeep_link_path%3D%2Fproduct%2F456"
For a more realistic test, uninstall the app, tap a Smart Link on the device, allow Linkzly to redirect you to the Play Store, then reinstall the app from the Play Store and open it. The referrer flow depends on Google Play Services and may not always be testable reliably on emulators.
Validate the assetlinks.json File
Use Google's Digital Asset Links API to validate your file before testing on a device:
# <span id="check-if-android-would-verify-your-domain-for-your-app"></span>Check if Android would verify your domain for your app
curl "https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://yourapp.linkz.ly&relation=delegate_permission/common.handle_all_urls"
Alternatively, use the visual tool at developers.google.com/digital-asset-links/tools/generator — enter your domain and package name to see if the file is valid and the fingerprint matches.
Troubleshooting
Android shows a disambiguation dialog instead of opening the app directly
- Confirm
android:autoVerify="true"is set on the intent filter inAndroidManifest.xml. - Check App Link verification with
adb shell pm get-app-links com.yourcompany.yourapp— the domain should showverified. - Verify the
assetlinks.jsonfile is accessible viacurland thepackage_nameandsha256_cert_fingerprintsvalues are correct. - Reinstall the app. Android verifies App Links at install time. Re-verification can also be triggered with
adb shell pm verify-app-links --re-verify.
Verification status shows none or legacy_failure
Common causes:
- The SHA-256 fingerprint in
assetlinks.jsondoes not match the certificate used to sign the installed APK. If you use Google Play App Signing, use the fingerprint from the Play Console, not your local keystore. - The
assetlinks.jsonfile returned a non-200 HTTP status, an empty body, or invalid JSON at verification time. Test withcurl. - There is a typo in
package_nameinassetlinks.json. It must match your app'sapplicationIdexactly. - The device could not reach the
assetlinks.jsonURL at install time. This can happen in restrictive network environments or on older Android versions.
App Link verification fails only on Play Store builds
This is almost always the Google Play App Signing fingerprint mismatch. Open Google Play Console → Setup → App integrity → App signing key certificate and add that SHA-256 fingerprint to your Linkzly app registration in addition to your local keystore fingerprint. Both will be included in assetlinks.json.
onNewIntent is not called — app restarts instead
Set android:launchMode="singleTask" (or singleTop) on your activity in the manifest. Without this, Android may launch a second instance of the activity when a new App Link arrives while the app is running, causing onCreate to be called instead of onNewIntent.
Deferred deep link referrer is empty
The Play Install Referrer is only populated when the user was redirected to the Play Store from a Smart Link. Direct Play Store installs (from search, browsing, or being featured) do not carry a referrer. Always check that the referrer string is non-empty before parsing it, and do not display an error to users when it is empty — this is the normal case for organic installs.
Deep link path extracted incorrectly
Log the full incoming URI in your intent handler to inspect what Linkzly is sending:
private fun handleDeepLinkIntent(intent: Intent) {
Log.d("DeepLink", "Received URI: ${intent.data}")
// ...
}
Verify the deep_link_path query parameter is present. In the Linkzly console, check the Smart Link's Deep Link Path field — the Advanced link type is required for path and data parameters to be forwarded to the app. Basic links do not include deep_link_path.
assetlinks.json cached stale values
Android caches the assetlinks.json file. After updating your app registration in Linkzly, force a fresh verification on the device:
adb shell pm verify-app-links --re-verify com.yourcompany.yourapp
This bypasses the device cache and fetches a fresh copy from the server.
Setup Checklist
- App registered in Linkzly console with the correct Package Name.
- SHA-256 fingerprint(s) added to the app registration — both debug keystore and the Google Play signing key fingerprint (if using Play App Signing).
-
assetlinks.jsonverified athttps://<your-domain>/.well-known/assetlinks.json—package_nameandsha256_cert_fingerprintsare correct. -
<intent-filter android:autoVerify="true">added toAndroidManifest.xmlfor each Linkzly domain. -
android:launchMode="singleTask"set on the activity inAndroidManifest.xml. -
android:exported="true"set on the activity (required on Android 12+). -
onCreate()callshandleDeepLinkIntent(intent). -
onNewIntent()callshandleDeepLinkIntent(intent). -
deep_link_pathquery parameter extracted and used for screen routing. - All expected deep link paths handled in the router — unknown paths fall back gracefully.
- App Link verification confirmed with
adb shell pm get-app-links— domain showsverified. - Tested with
adb shell am start— correct screen opens with expected parameters. - Deferred deep link handling implemented with the Play Install Referrer library and guarded with a one-time processed flag.
- Google Play URL set in Linkzly app registration for the deferred deep link redirect to work.
Was this helpful?
Help us improve our documentation