Skip to main content

Working with App Links

Feature Deep Links App Links
URL Scheme myapp://screen1 https://www.example.com/screen1
Domain Verification Not required Required for Android 6.0+
User Experience May prompt user to choose app Directly opens the app if installed
Security Less secure, no verification More secure with domain ownership proof
Fallback Behavior May not open app if not installed Can fall back to web page if app not present
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("myapp://screen1"))
startActivity(intent)
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com/screen1"))
startActivity(intent)

2. Configuring Intent Filters

Filter Type Configuration Description
intent-filter <intent-filter> Defines a set of actions, categories, and data that an activity can handle.
action <action android:name="android.intent.action.VIEW" /> Specifies the action that the intent filter handles, such as viewing a web page.
category <category android:name="android.intent.category.DEFAULT" /> Indicates that the component can be used as a default handler for an intent.
data <data android:scheme="https" android:host="example.com" /> Specifies the type of data that the intent filter can handle, such as a URL scheme and host.

Example: Intent Filter Configuration

<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="example.com" />
    </intent-filter>
</activity>

Asset Links files are used to verify that your app is authorized to handle specific URLs. They must be hosted at https://yourdomain.com/.well-known/assetlinks.json.

Field Description Required
relation Specifies the action the app can perform. Must include delegate_permission/common.handle_all_urls. Yes
target Defines the app and its signature hash. Yes

Example: assetlinks.json

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.app",
      "sha256_cert_fingerprints": ["AB:CD:E1:F2:G3:H4:I5:J6:K7:L8:M9:N0:O1:P2:Q3:R4:S5:T6:U7:V8:W9:X0:Y1:Z2"]
    }
  }
]
Note: The SHA-256 fingerprint can be obtained using the command keytool -list -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android.
Property Value Description
assetlinks.json /.well-known/assetlinks.json Location where the digital asset links file is hosted
formatVersion 1 Version of the asset links format
packageName com.example.app Package name of the Android app
sha256Fingerprints [SHA256_FINGERPRINT] SHA-256 fingerprint of the app's signing certificate

Example: assetlinks.json content

{
  "formatVersion": "1",
  "packageName": "com.example.app",
  "sha256Fingerprints": [
    "A1:B2:C3:D4:E5:F6:G7:H8:I9:J0:K1:L2:M3:N4:O5:P6:Q7:R8:S9:T0:U1:V2:W3:X4:Y5:Z6"
  ]
}
Note: The assetlinks.json file must be hosted at the root of your domain under /.well-known/assetlinks.json.
Warning: Ensure the SHA-256 fingerprint matches exactly with the app's signing certificate. Any mismatch will cause App Links to fail.

Verifying App Links ensures that your app correctly handles deep links and maintains security by validating the association between your app and web content.

Verification Method Description Notes
App Links Assistant Tool in Android Studio to analyze and verify App Links configuration. Available in Android Studio Arctic Fox and later versions.
Digital Asset Links JSON file hosted on your website to declare app-to-web associations. Must be accessible at https://yoursite.com/.well-known/assetlinks.json.
Intent Filters Define in AndroidManifest.xml to handle deep links. Must include android:autoVerify="true" for automatic verification.

Example: Intent Filter with Auto-Verification

<activity
    android:name=".MainActivity"
    android:autoVerify="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="yourdomain.com" />
    </intent-filter>
</activity>
Note: The android:autoVerify="true" attribute enables automatic verification of App Links by the system.
Warning: If your app's intent filters do not match the digital asset links file, the system will not verify the App Links and may open the URL in a browser instead.
Property Description Example
intent.action.VIEW Used to handle incoming links in Android apps. val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
intent.data Represents the URI of the incoming link. val uri = intent.data
intent.getParcelableExtra() Used to retrieve data passed through the intent. val data = intent.getParcelableExtra<MyData>("data")
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intent = intent
        if (Intent.ACTION_VIEW == intent.action) {
            val uri = intent.data
            uri?.let {
                // Handle the incoming link
                handleIncomingLink(it)
            }
        }
    }

    private fun handleIncomingLink(uri: Uri) {
        // Process the link
        val path = uri.path
        val query = uri.query
    }
}
Note: Ensure that your app's manifest includes the appropriate intent filters to handle incoming links.
Property Description Example
deepLink URI pattern to match for deep linking android-app://com.example.app/feature?id=123
navigationGraph Resource ID of the navigation graph file R.navigation.nav_graph
uri Full URI to navigate to https://example.com/deeplink
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph">

    <deepLink
        android:id="@+id/deep_link"
        app:uri="https://example.com/deeplink" />

</navigation>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navController = findNavController(R.id.nav_host_fragment)
        val navGraph = navController.navInflater.inflate(R.navigation.nav_graph)

        // Handle deep link
        val deepLink = intent.data
        if (deepLink != null) {
            navController.setGraph(navGraph, deepLink)
        }
    }
}

Deferred deep links allow you to redirect users to a specific part of your app even if they don't have the app installed. When a user clicks on a link, they are first directed to the web page and then, if the app is installed, redirected to the appropriate screen within the app.

Property Description Example
android:autoVerify Enables automatic verification of app links. <intent-filter android:autoVerify="true">
android:webAppManifest Points to the web app manifest file for deferred deep links. <meta-data android:name="android.webkit.WebAppManifest" android:value="@xml/web_app_manifest">
<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter
        android:autoVerify="true"
        android:label="@string/app_name">
        <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="example.com" />
    </intent-filter>
</activity>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intent = intent
        if (Intent.ACTION_VIEW == intent.action) {
            val uri = intent.data
            // Handle the deep link here
            handleDeepLink(uri)
        }
    }

    private fun handleDeepLink(uri: Uri?) {
        // Process the deep link and navigate to appropriate screen
        uri?.let { 
            val path = it.path
            // Navigate based on the path or query parameters
        }
    }
}
Note: Ensure that your app's domain is verified with Google to support deferred deep links effectively.
Warning: Make sure the android:autoVerify is set to true for automatic verification of app links.
class AppLinkTest {
    @Test
    fun testAppLinkHandling() {
        val intent = Intent(
            Intent.ACTION_VIEW,
            Uri.parse("https://example.com/deep-link")
        )
        intent.addCategory(Intent.CATEGORY_DEFAULT)
        intent.addCategory(Intent.CATEGORY_BROWSABLE)
        intent.setPackage("com.example.app")

        val resolvedActivity = context.packageManager.resolveActivity(
            intent,
            PackageManager.MATCH_DEFAULT_ONLY
        )

        assertNotNull(resolvedActivity)
        assertEquals("com.example.app", resolvedActivity?.activityInfo?.packageName)
    }
}
Test Type Description Notes
Instrumentation Tests Use Espresso to test deep link handling in the app. Requires AndroidJUnitRunner
Unit Tests Use Robolectric to simulate app link handling without device. Fast, no device required

Testing Workflow

  1. Create a test intent with the deep link URL
  2. Add CATEGORY_BROWSABLE and CATEGORY_DEFAULT
  3. Set the package name to your app
  4. Resolve activity using PackageManager
  5. Assert that the correct activity is resolved
Note: Ensure your app's manifest includes the correct intent filters for deep links to be properly handled.
adb shell am start -W -a android.intent.action.VIEW -c android.intent.category.DEFAULT -d "https://example.com" com.example.app
Command Description Notes
adb shell am start Starts an intent from the command line Useful for testing App Link behavior
-W Wait for the activity to be launched Helps in debugging timing issues
-a android.intent.action.VIEW Specifies the intent action to view a URL Essential for App Link testing
-d https://example.com Data URI to test Replace with actual URL to verify
Note: Ensure your app's manifest includes the correct intent filters for App Links to be handled properly.
Warning: App Link verification can be affected by network conditions and app state. Always test in a clean environment.

Debugging Steps

  • Check manifest for proper intent filters
  • Verify domain verification files are accessible
  • Use adb to simulate App Link launch
  • Review logs for errors or warnings

Was this article helpful?