Skip to content

Most visited

Recently visited

navigation

Verify Android App Links

Android App Links are a special type of deep link that allow your website URLs to immediately open the corresponding content in your Android app (without requiring the user to select the app).

To add Android App Links to your app, define intent filters that open your app content using HTTP URLs (as described in Create Deep Links to App Content), and verify that you own both your app and the website URLs (as described in this guide). If the system successfully verifies that you own the URLs, the system automatically routes those URL intents to your app.

To verify ownership of both your app and your website, the following steps are required:

The difference between deep links and app links

A deep link is an intent filter that allows users to directly enter a specific activity in your Android app. Clicking one of these links might open a disambiguation dialog, which allows the user to select one of multiple apps (including yours) that can hande the given URL. For example, figure 1 shows the disambiguation dialog after the user clicks a map link, asking whether to open the link in Maps or Chrome.

Figure 1. The disambiguation dialog

An Android App Link is a deep link based on your website URL that has been verified to belong to your website. So clicking one of these immediately opens your app if it's installed—the disambiguation dialog does not appear. Though the user may later change their preference for handling these links.

The following table describes more specific differences.

Deep linksApp links
Intent URL scheme http, https, or a custom scheme Requires http or https
Intent action Any action Requires android.intent.action.VIEW
Intent category Any category Requires android.intent.category.BROWSABLE and android.intent.category.DEFAULT
Link verification None Requires a Digital Asset Links file served on you website with HTTPS
User experience May show a disambiguation dialog for the user to select which app to open the link No dialog; your app opens to handle your website links
Compatibility All Android versions Android 6.0 and higher

Request app links verification

To enable link handling verification for your app, set android:autoVerify="true" in any one of the web URL intent filters in your app manifest that include the android.intent.action.VIEW intent action and android.intent.category.BROWSABLE intent category, as shown in the following manifest code snippet:

<activity ...>

    <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="http" android:host="www.example.com" />
        <data android:scheme="https" />
    </intent-filter>

</activity>

When android:autoVerify="true" is present on any one of your intent filters, installing your app on devices with Android 6.0 and higher causes the system to attempt to verify all hosts associated with the URLs in any of your app's intent filters. Verification involves the following:

  1. The system inspects all intent filters that include:
    • Action: android.intent.action.VIEW
    • Categories: android.intent.category.BROWSABLE and android.intent.category.DEFAULT
    • Data scheme: http or https
  2. For each unique host name found in the above intent filters, Android queries the corresponding websites for the Digital Asset Links file at https://hostname/.well-known/assetlinks.json.

Only if the system finds a matching Digital Asset Links file for all hosts in the manifest does it then establish your app as the default handler for the specified URL patterns.

Supporting app linking for multiple hosts

The system must be able to verify every host specified in the app’s URL intent filters’ data elements against the Digital Asset Links files hosted on all the respective web domains. If any verification fails, the app is not verified to be a default handler for any of the URL patterns defined in the app's intent filters. The system then defaults to its standard behavior to resolve the intent, as described in Create Deep Links to App Content.

For example, an app with the following intent filters would fail verification if an assetlinks.json file were not found at both https://www.example.com/.well-known/assetlinks.json and https://www.example.net/.well-known/assetlinks.json:

<application>

  <activity android:name=”MainActivity”>
    <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="http" android:host="www.example.com" />
      <data android:scheme="https" />
    </intent-filter>
  </activity>
  <activity android:name=”SecondActivity”>
    <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.net" />
    </intent-filter>
  </activity>

</application>

Remember that all <data> elements in the same intent filter are merged together to account for all variations of their combined attributes. For example, the first intent filter above includes a <data> element that only declares the HTTPS scheme. But it is combined with the other <data> element so that the intent filter supports both http://www.example.com and https://www.example.com. As such, you must create separate intent filters when you want to define specific combinations of URI schemes and domains.

Supporting app linking for multiple subdomains

The Digital Asset Links protocol treats subdomains in your intent filters as unique, separate hosts. So if your intent filter lists multiple hosts with different subdomains, you must publish a valid assetlinks.json on each domain. For example, the following intent filter includes www.example.com and mobile.example.com as accepted intent URL hosts. So a valid assetlinks.json must be published at both https://www.example.com/.well-known/assetlinks.json and https://mobile.example.com/.well-known/assetlinks.json.

<application>
  <activity android:name=”MainActivity”>
    <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="www.example.com" />
      <data android:scheme="https" android:host="mobile.example.com" />
    </intent-filter>
  </activity>
</application>

Alternatively, if you declare your hostname with a wildcard (such as *.example.com), you must publish your assetlinks.json file at the root hostname (example.com). For example, an app with the following intent filter will pass verification for any sub-name of example.com (such as foo.example.com) as long as the assetlinks.json file is published at https://example.com/.well- known/assetlinks.json:

<application>
  <activity android:name=”MainActivity”>
    <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="*.example.com" />
    </intent-filter>
  </activity>
</application>

Declare website associations

A Digital Asset Links JSON file must be published on your website to indicate the Android apps that are associated with the website and verify the app's URL intents. The JSON file uses the following fields to identify associated apps:

The following example assetlinks.json file grants link-opening rights to a com.example Android app:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

Associating a website with multiple apps

A website can declare associations with multiple apps within the same assetlinks.json file. The following file listing shows an example of a statement file that declares association with two apps, separately, and resides at https://www.example.com/.well-known/assetlinks.json:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.puppies.app",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
  },
  {
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.monkeys.app",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

Different apps may handle links for different resources under the same web host. For example, app1 may declare an intent filter for https://example.com/articles, and app2 may declare an intent filter for https://example.com/videos.

Note: Multiple apps associated with a domain may be signed with the same or different certificates.

Associating multiple websites with a single app

Multiple websites can declare associations with the same app in their respective assetlinks.json files. The following file listings show an example of how to declare the association of example.com and example.net with app1. The first listing shows the association of example.com with app1:

https://www.example.com/.well-known/assetlinks.json

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.mycompany.app1",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

The next listing shows the association of example.net with app1. Only the location where these files are hosted is different (.com and .net):

https://www.example.net/.well-known/assetlinks.json

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.mycompany.app1",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

Publishing the JSON verification file

You must publish your JSON verification file at the following location:

https://domain.name/.well-known/assetlinks.json

Be sure of the following:

Test app links

When implementing the app linking feature, you should test the linking functionality to make sure the system can associate your app with your websites, and handle URL requests, as you expect.

To test an existing statement file, you can use the Statement List Generator and Tester tool.

Confirm the list of hosts to verify

When testing, you should confirm the list of associated hosts that the system should verify for your app. Make a list of all URLs whose corresponding intent filters include the following attributes and elements:

Use this list to check that a Digital Asset Links JSON file is provided on each named host and subdomain.

Confirm the Digital Asset Links files

For each website, use the Digital Asset Links API to confirm that the Digital Asset Links JSON file is properly hosted and defined:

https://digitalassetlinks.googleapis.com/v1/statements:list?
   source.web.site=https://domain.name:optional_port&
   relation=delegate_permission/common.handle_all_urls

Testing a URL intent

Once you have confirmed the list of websites to associate with your app, and you have confirmed that the hosted JSON file is valid, install the app on your device. Wait at least 20 seconds for the asynchronous verification process to complete. Use the following command to check whether the system verified your app and set the correct link handling policies:

adb shell am start -a android.intent.action.VIEW \
    -c android.intent.category.BROWSABLE \
    -d "http://domain.name:optional_port"

As part of your testing process, you can check the current system settings for link handling. Use the following command to get a listing of existing link-handling policies for all apps on your connected device:

adb shell dumpsys package domain-preferred-apps

Or the following does the same thing:

adb shell dumpsys package d

Note: Make sure you wait at least 20 seconds after installation of your app to allow for the system to complete the verification process.

The command returns a listing of each user or profile defined on the device, preceded by a header in the following format:

App linkages for user 0:

Following this header, the output uses the following format to list the link-handling settings for that user:

Package: com.android.vending
Domains: play.google.com market.android.com
Status: always : 200000002

This listing indicates which apps are associated with which domains for that user:

Note: If a user changes the app link settings for an app before verification is complete, you may see a false positive for a successful verification, even though verification has failed. This verification failure, however, does not matter if the user explicitly enabled the app to open supported links without asking. This is because user preferences take precedence over programmatic verification (or lack of it). As a result, the link goes directly to your app, without showing a dialog, just as if verification had succeeded.

Test example

For app link verification to succeed, the system must be able to verify your app with all of the websites that you specify in your app’s intent filters, and that meet the criteria for app links. The following example shows a manifest configuration with several app links defined:

<application>

    <activity android:name=”MainActivity”>
        <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="www.example.com" />
            <data android:scheme="https" android:host="mobile.example.com" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" android:host="www.example2.com" />
        </intent-filter>
    </activity>

    <activity android:name=”SecondActivity”>
        <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="account.example.com" />
        </intent-filter>
    </activity>

      <activity android:name=”ThirdActivity”>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="https" android:host="map.example.com" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="market" android:host="example.com" />
        </intent-filter>
      </activity>

</application>

The list of hosts that the platform would attempt to verify from the above manifest is:

www.example.com
mobile.example.com
www.example2.com
account.example.com

The list of hosts that the platform would not attempt to verify from the above manifest is:

map.example.com (it does not have android.intent.category.BROWSABLE)
market://example.com (it does not have either an “http” or “https” scheme)
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)