Welcome to Android 12 Developer Preview! Please give us feedback early and often, and help us make Android 12 the best release yet!

Web intent resolution

Starting in Android 12, a generic web intent can resolve to an activity in your app only if your app is approved for the specific domain contained in that web intent. If your app isn't approved for the domain, the web intent resolves to the user's default browser app instead.

Apps can get this approval by doing one of the following:

If your app invokes web intents, consider adding a prompt or dialog that asks the user to confirm the action.

Web intent attributes

A web intent is an intent that contains the following characteristics:

Web intent filters must include the browsable category

Starting in Android 12, web intent filters must also declare the CATEGORY_BROWSABLE category in order for a given web intent to resolve to an activity in your app.

Android App Links, available in Android 8.0 (API level 26) and higher, use the Digital Asset Links API to associate a specific app with a web domain. This association allows the system to trust that the app has been approved by the website to automatically open links for that domain.

Starting in Android 12, you can manually invoke domain verification to evaluate how the system resolves your Android App Links.

On apps that target Android 12, the system makes several changes to how Android App Links are verified. These changes improve the reliability of the app-linking experience and provide more control to app developers and end users.

If you target Android 12 and rely on Android App Link verification to open web links in your app, update your Android App Links declarations to support the changed verification process. You can also manually invoke domain verification to test the reliability of your declarations.

Update declarations of Android App Links

The domain verification process requires an internet connection and could take some time to complete. To help improve the efficiency of the process, the system verifies a domain for an app that targets Android 12 only if that domain is inside a specifically-formatted <intent-filter> element. The <intent-filter> element must contain the actions, categories, and schemes that are shown in the following snippet:

<!-- Make sure you explicitly set android:autoVerify to "true". -->
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <!-- If a user clicks on a shared link that uses the "http" scheme, your
         app should be able to delegate that traffic to "https". -->
    <data android:scheme="http" />
    <data android:scheme="https" />

    <!-- Include one or more domains that should be verified. -->
    <data android:host="..." />
</intent-filter>

Manually invoke domain verification

Starting in Android 12, you can manually invoke domain verification for an app that's installed on a device. You can perform this process regardless of whether your app targets Android 12.

Establish an internet connection

To perform domain verification, your test device must be connected to the internet.

Support the updated domain verification process

If your app targets Android 12, the system uses the updated domain verification process automatically.

Otherwise, you can manually enable the updated verification process. To do so, run the following command in a terminal window:

adb shell am compat enable 175408749 PACKAGE_NAME

Reset the state of Android App Links on a device

Before you manually invoke domain verification on a device, you must reset the state of Android App Links on the test device. To do so, run the following command in a terminal window:

adb shell pm set-app-links --package PACKAGE_NAME 0 all

This command puts the device in the same state that it's in before the user chooses default apps for any domains.

Invoke the domain verification process

After you reset the state of Android App Links on a device, you can perform the verification itself. To do so, run the following command in a terminal window:

adb shell pm verify-app-links --re-verify PACKAGE_NAME

Review the verification results

After allowing some time for the verification agent to finish its requests, review the verification results. To do so, run the following command:

adb shell pm get-app-links PACKAGE_NAME

The output of this command is similar to the following:

com.example.pkg:
    ID: 01234567-89ab-cdef-0123-456789abcdef
    Signatures: [***]
    Domain verification state:
      example.com: verified
      sub.example.com: legacy_failure
      example.net: verified
      example.org: 1026

The domains that successfully pass verification have a domain verification state of verified. Any other state indicates that the domain verification couldn't be performed. In particular, a state of none indicates that the verification agent might not have completed the verification process yet.

The following list shows the possible return values that domain verification can return for a given domain:

none
Nothing has been recorded for this domain. Wait a few more minutes for the verification agent to finish the requests related to domain verification, then invoke the domain verification process again.
verified
The domain is successfully verified for the declaring app.
approved
The domain was force-approved, usually by executing a shell command.
denied
The domain was force-denied, usually by executing a shell command.
migrated
The system preserved the result of a previous process that used legacy domain verification.
restored
The domain was approved after the user performed a data restore. It's assumed that the domain was previously verified.
legacy_failure
The domain was rejected by a legacy verifier. The specific failure reason is unknown.
system_configured
The domain was approved automatically by the device configuration.
Error code of 1024 or greater

Custom error code that's specific to the device's verifier.

Double-check that you have established a network connection, and invoke the domain verification process again.

Request the user to associate your app with a domain

Another way for your app to get approved for a domain is to ask the user to associate your app with that domain.

Check whether your app is already approved for the domain

Before you prompt the user, check whether your app is the default handler for the domains that you define in your <intent-filter> elements. You can query the approval state using one of the following methods:

DomainVerificationManager

The following code snippet demonstrates how to use the DomainVerificationManager API:

val context: Context = TODO("Your activity or fragment's Context")
val manager = context.getSystemService(DomainVerificationManager::class)
val userState = manager.getDomainVerificationUserState(context.packageName)
val verifiedDomains = userState.hostToStateMap
    .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED }
val selectedDomains = userState.hostToStateMap
    .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_SELECTED }
val unapprovedDomains = userState.hostToStateMap
    .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_NONE }

Command-line program

When testing your app during development, you can run the following command to query the verification state of the domains that your organization owns:

adb shell pm get-app-links --user cur PACKAGE_NAME

In the following example output, even though the app failed verification for the "example.org" domain, user 0 has manually approved the app in system settings, and no other package is verified for that domain.

com.example.pkg:
ID: ***
Signatures: [***]
Domain verification state:
  example.com: verified
  example.net: verified
  example.org: 1026
User 0:
  Verification link handling allowed: true
  Selection state:
    Enabled:
      example.org
    Disabled:
      example.com
      example.net

Provide context for the request

Before you make this request for domain approval, provide some context for the user. For example, you might show them a splash screen, a dialog, or a similar UI element that explains to the user why your app should be the default handler for a particular domain.

Make the request

After the user understands what your app is asking them to do, make the request. To do so, invoke an intent that includes the ACTION_APP_OPEN_BY_DEFAULT_SETTINGS intent action, and a data string matching package:com.example.pkg for the target app, as shown in the following code snippet:

val context: Context = TODO("Your activity or fragment's Context")
val intent = Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
    Uri.parse("package:${context.packageName}"))
context.startActivity(intent)

When the intent is invoked, users see a settings screen called Open by default. This screen contains a radio button called Open supported links, as shown in figure 1.

When the user enables Open supported links, a set of checkboxes appear under a section called Links to open in this app. From here, users can select the domains that they want to associate with your app. They can also select Add link to add domains, as shown in figure 2. When users later select any link within the domains that they add, the link opens in your app automatically.

When the radio button is enabled, a section near the bottom
    includes checkboxes as well as a button called 'Add link'
Figure 1. System settings screen where users can choose which links open in your app by default.
Each checkbox represents a domain that you can add. The
    dialog's buttons are 'Cancel' and 'Add.'
Figure 2. Dialog where users can choose additional domains to associate with your app.

Toggle domain approval manually

Both domain verification and user selection can be toggled using shell commands which allow a developer to manually set the appropriate state for debugging, running tests, or for cases like no internet connectivity.

A full explanation of these commands is available from the output of adb shell pm.

Note that all of the same verified precedence and single approval restrictions apply even when approved through the shell commands, so some special cases like installing two app variants simultaneously require special handling to open a given web link in the intended app.

Special cases

Because of the changes made to improve the UX and avoid showing the intent picker, there are a few special cases which need to be considered.

Multiple verified apps

If you ship multiple apps which each verify for the same domain, they can both be successfully verified. However, they cannot both resolve the same intent; instead, the app that was installed last is preferred.

This applies only in cases where both apps resolve the same exact domain host and path, such as when both a Lite and Full version of an app is shipped, and a user has both installed.

In a case like this, with multiple apps that may be conflicting, check for these other apps on the user's device, provided that you have the necessary package visibility. Then, in your app, show a custom chooser dialog that contains the results from calling queryIntentActivities(). The user can select their preferred app from the list of matching apps that appear in the dialog.

Unverified apps

If your app's main function is to open links as a third party, without access to verify its handled domains, you may need to explain this to the user. The user can then understand that using both a first-party app for the website and your third-party app simultaneously to open links is not supported. They need to disable the first-party app in order to approve its verified domains for your (third-party) app.

In addition, consider introducing a dialog or trampoline activity that allows the user to open the link in the first-party app if the user prefers to do so, acting as a proxy. Before setting up such a dialog or trampoline activity, set up your app so that it has package visibility into the first-party apps that match your app's web intent filter.