To support App Links, you must create a Digital Asset Links
JSON file called assetlinks.json
and publish it in a well-known location on
your website. This file publicly declares which apps are authorized to handle
links for your domain, and Android devices will retrieve this file from your
server to verify your deep links.
For dynamic App Links in Android 15+, the assetlinks.json
file is also
where you define your dynamic rules configuration, such as pattern matchers
for path, fragment, and query parameters. Android devices running Android 15
(API level 35) or later that have Google services installed will periodically
retrieve the file and merge your dynamic configuration with the static
configuration in the app's manifest.
This guide describe how to prepare an assetlinks.json
file and publish
it on your website. If you prefer, you can generate an assetlinks.json
file from the Play Deep Links tool or the Android Studio App Links Assistant.
For more information, see App Links developer tools.
Declare website associations
You must publish a Digital Asset Links JSON file 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:
package_name
: The application ID declared in the app'sbuild.gradle
file.sha256_cert_fingerprints
: The SHA256 fingerprints of your app's signing certificate. You can use the following command to generate the fingerprint using the Java keytool:
keytool -list -v -keystore my-release-key.keystore
- This field supports multiple fingerprints, which can be used to support
different versions of your app, such as debug and production builds. If you're
using Play App Signing for your app, then the certificate
fingerprint produced by running
keytool
locally will usually not match the one on users' devices. You can verify whether you're using Play App Signing for your app in your Play Console developer account underRelease > Setup > App signing
; if you do, then you'll also find the correct Digital Asset Links JSON snippet for your app on the same page.
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"]
}
}]
Associate 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
.
Associate 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"]
}
}]
Configure dynamic rules
Dynamic App Links in Android 15+ lets you use server-side deep link matching
rules that work together with the rules you've defined statically in your app
manifest. Your assetlinks.json
file is where you define dynamic rules. This
is optional to include.
Android devices running Android 15 (API level 35) or later that have Google
services installed will periodically retrieve this file from your server and
merge your dynamic rules configuration with the static configuration in the
app's manifest. The following is an example of an assetlinks.json
file with
dynamic rules:
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": [...]
},
"relation_extensions": {
"delegate_permission/common.handle_all_urls": {
"dynamic_app_link_components": [
{"?": {"dl": "*"}},
{"#": "app"},
{"/": "/products/*"},
{"/": "/shoes", "?": {"in_app": "true"}},
{"/": "*", "exclude": true}
]
}
}
}
]
Key points about the code
- Dynamic App Links adds a new Digital Asset Links relation extension called
dynamic_app_link_components
, which is where you configure your dynamic rules. - Dynamic rules can include pattern matchers for path, fragment, and query parameters.
- You can also mark any pattern matcher as excluded, so that matching URLs don't open your app.
- This example shows examples of matchers for path (
"/"
), fragment ("#"
), and query parameters ("?"
), and also excluded matchers ("exclude"
) - If any of the fields in the file are malformed or empty, Android discards the dynamic rules and the device falls back to the rules that are statically defined in the app's manifest.
Dynamic rules can only specify rules that apply within the scope of the domains that you declare in your app's manifest file. See below.
Declare dynamic rules
Dynamic App Links supports a new dynamic_app_link_components
relation
extension, which holds an array of rules objects. Each rule is defined using
pattern matchers for paths, fragments, and query parameters that will open your
app. Matchers can also be individually excluded so that they will not open your
app. All of these are optional.
- Path matching
- Key: "/"
- Value: Single string, matching expression for the URL path
- Fragment matching
- Key: "#"
- Value: Single string, matching expression for the URL fragment
- Query parameter matching
- Key: "?"
- Value: Dictionary to match key/value pairs in the URL query parameters.
- For example the dictionary {"
?", {"dl": "*", "in_app":"true
"} will match the query string "?in_app=true&dl=abc
". - The order of key/value pairs in the dictionary does not need to match the order of the pairs in the query string. Additionally, the dictionary does not need to match all key/value pairs in the query string, but a match must be found for every dictionary entry.
- For example the dictionary would also match the query string
"
?lang=en&in_app=true&tz=pst&dl=abc
", but not match the query string "?lang=en&tz=pst&dl=abc
"
- Excluded
- Key: "exclude"
- Value: Optional true/false value for each rule defined in
dynamic_app_link_components
(see example).
You can use these special characters in pattern matchers:
- "*" matches zero or more characters up until the character after the wildcard in the pattern is found in the matching string
- "?" matches any single character
- "?*" matches 1 or more characters
There are no other character restrictions for values.
Order dynamic rules
The order in which the rules are declared matters. Android evaluates each rule in order until it finds a match.
The following example shows how ordering can affect handling. The first rule matches all paths ("*") but excludes matches (exclude: true), meaning that it excludes all URLs from opening the app. In this case, the second rule that allows "/path1" will never be evaluated.
dynamic_app_link_components: [
{"/": "*", exclude: true},
{"/": "/path1"}
]
However, in the next example, the "/path1" rule is declared first, so it will be evaluated first and will open the app for a URL matching "/path1". The second rule, that excludes all URLs from opening the app, will be evaluated second, but only if the first rule is not a match.
dynamic_app_link_components: [
{"/": "/path1"},
{"/": "*", exclude: true}
]
Properly scope your dynamic rules
When defining your server-side rules for use with Dynamic App Links in Android 15 and higher, it's important to scope them appropriately, so that they work with and complement the static intent filters declared in your app manifest.
Dynamic rules declared in the assetlinks.json file can only specify rules for
the hosts that you declare in your app's AndroidManifest.xml
file. The dynamic
rules cannot expand the scope of the URL rules that you declare statically in
your app manifest.
For this reason, we recommend using this approach across your dynamic and static rules:
- In your app manifest, set rules with the broadest possible scope, such as by declaring scheme and domain only
- Rely on the server-side dynamic rules for further refinement, such as path-level routing.
With this ideal configuration, you will be able to dynamically add new App Links paths in the assetlinks.json file as needed, knowing that they will fit within the broad scope that you've set in the app manifest.
Declare dynamic_app_link_components only once
For proper handling of your rules, declare only one dynamic_app_link_components object across the statements for a given site, relation, and app.
- Look for multiple statements for the same site, relation, and app, that declare a dynamic_app_link_components object.
- Look for multiple dynamic_app_link_components objects that are declared in a single statement
In cases like these, Android does not guarantee which dynamic rules configuration will be used.
Dynamic rules compatibility with earlier App Links configurations
If you are already supporting App Links, you can add support for Dynamic App Links directly in your existing assetlinks.json file. The relation fields for verifying your App Links remain the same, and you can add the new relation extension fields for dynamic rules without any other changes.
Android devices running Android 14 (API level 34 or earlier) ignore the new relation extension fields for dynamic rules, while devices running Android 15 and later will merge those rules with your manifest-defined rules.
Publish 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:
- The
assetlinks.json
file is served with content-typeapplication/json
. - The
assetlinks.json
file must be accessible over an HTTPS connection, regardless of whether your app's intent filters declare HTTPS as the data scheme. - The
assetlinks.json
file must be accessible without any redirects (no 301 or 302 redirects). - If your app links support multiple host domains, then you must publish the
assetlinks.json
file on each domain. See Supporting app linking for multiple hosts. - Don't publish your app with test URLs in the manifest file that may not be accessible to the public (such as any that are accessible only with a VPN). A work-around in such cases is to configure build variants to generate a different manifest file for dev builds.
See the following related guides: