This document presents several common examples of use cases in which an app interacts with other apps. Each section provides guidance on how to declare package visibility of other installed apps, which you need to consider if your app targets Android 11 (API level 30) or higher.
When your app targets Android 11 or higher and uses an intent to
start an activity in another app, the most straightforward approach is to invoke
the intent and handle the
ActivityNotFoundException
exception if no app is available.
If part of your app depends on knowing whether the call to
startActivity()
can succeed, such as showing a UI, add an element to the
<queries>
element of your app's
manifest. Typically, this new element is an <intent>
element.
Open URLs
This section describes how to open URLs in an app that targets Android 11 or higher. Follow one of the examples in the following subsections, depending on how your app opens URLs.
Open URLs in a browser or other app
To open a URL, use an intent that contains the ACTION_VIEW
intent action, as
described in the section about how to load a web
URL. After you call startActivity()
using this intent, one of the following happens:
- The URL opens in a web browser app.
- The URL opens in an app that supports the URL as a deep link.
- A disambiguation dialog appears, which allows the user to choose which app opens the URL.
An
ActivityNotFoundException
occurs because there isn't any app installed on the device that can open the URL. (This is unusual.)It's recommended that your app catch and handle the
ActivityNotFoundException
if it occurs.
Because the startActivity()
method is unaffected by the system's package
visibility behavior, you don't need to add a <queries>
element to your app's
manifest, or make any changes to an existing <queries>
element.
Check if a browser is available
In some cases, your app might want to verify that there's at least one browser
available on the device, or that a specific browser is the default browser,
before attempting to open a URL. In that case, include the following <intent>
element as part of the <queries>
element in your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent>
When you call queryIntentActivities()
and pass a web intent as an argument,
the returned list includes the available browser apps in some cases. The list
doesn't include browser apps if the user has configured the URL to open in a
non-browser app by default.
Open URLs in Custom Tabs
Custom Tabs allow an
app to customize how the browser looks and feels. You can open a URL in
a Custom Tab
without needing to add or change the <queries>
element in your app manifest.
However, you might want to check whether the device has a browser that supports
Custom Tabs,
or select a specific browser to launch with Custom Tabs using
CustomTabsClient.getPackageName()
.
In those cases, include the following <intent>
element as part of the
<queries>
element in your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.support.customtabs.action.CustomTabsService" /> </intent>
Let non-browser apps handle URLs
Even if your app can open URLs using Custom Tabs, it's recommended that you
allow a non-browser app to open a given URL if possible. To provide this
capability in your app, attempt a call to startActivity()
using an intent
that sets the
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
intent flag. If the system throws an ActivityNotFoundException
, your app can
then open the URL in a Custom Tab.
If an intent includes this flag, a call to startActivity()
causes an
ActivityNotFoundException
to be thrown when either of the following
conditions occurs:
- The call would have launched a browser app directly.
- The call would have shown a disambiguation dialog to the user, where the only options are browser apps.
The following code snippet shows how to update your logic to use the
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
intent flag:
Kotlin
try { val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { // The URL should either launch directly in a non-browser app (if it's // the default), or in the disambiguation dialog. addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER } startActivity(intent) } catch (e: ActivityNotFoundException) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url) }
Java
try { Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); // The URL should either launch directly in a non-browser app (if it's the // default), or in the disambiguation dialog. intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER); startActivity(intent); } catch (ActivityNotFoundException e) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url); }
Avoid a disambiguation dialog
If you want to avoid showing the disambiguation dialog that users might see when
they open a URL, and instead prefer to handle the URL yourself in these
situations, you can use an intent that sets the
FLAG_ACTIVITY_REQUIRE_DEFAULT
intent flag.
If an intent includes this flag, a call to startActivity()
causes an
ActivityNotFoundException
to be thrown when the call would have shown a
disambiguation dialog to the user.
If an intent includes both this flag and the
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
intent flag, a call to startActivity()
causes an ActivityNotFoundException
to be thrown when either of the following conditions occurs:
- The call would have launched the browser app directly.
- The call would have shown a disambiguation dialog to the user.
The following code snippet shows how to use the FLAG_ACTIVITY_REQUIRE_NON_BROWSER
and FLAG_ACTIVITY_REQUIRE_DEFAULT
flags together:
Kotlin
val url = URL_TO_LOAD try { // In order for this intent to be invoked, the system must directly launch a // non-browser app. val intent = Intent(ACTION_VIEW, Uri.parse(url).apply { addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or FLAG_ACTIVITY_REQUIRE_DEFAULT } startActivity(intent) } catch (e: ActivityNotFoundException) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url) }
Java
String url = URL_TO_LOAD; try { // In order for this intent to be invoked, the system must directly launch a // non-browser app. Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER | FLAG_ACTIVITY_REQUIRE_DEFAULT); startActivity(intent); } catch (ActivityNotFoundException e) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url); }
Open a file
If your app handles files or attachments, such as checking if a device can open
a given file, it's usually easiest to try to start an activity that can handle
the file. To do so, use an intent that includes the ACTION_VIEW
intent action
and the URI that represents the specific file. If no app is available on the
device, your app can catch the ActivityNotFoundException
. In your
exception-handling logic, you can either show an error or try to handle the file
yourself.
If your app must know in advance whether another app can open a given file,
include the <intent>
element in the following code snippet as part of the
<queries>
element in your manifest. Include the file type if you already know
what it is at compile time.
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". --> <data android:mimeType="application/pdf" /> </intent>
You can then check if an app is available by calling resolveActivity()
with
your intent.
Grant URI access
Note: This recommendation applies to all apps, regardless of the following:
- Your app's target SDK version.
- Whether your app exports its content provider.
In order for apps that target Android 11 or higher to be able to
access the content URI, your app's intent must declare URI access
permissions
by setting at least one of the following intent flags:
FLAG_GRANT_READ_URI_PERMISSION
and
FLAG_GRANT_WRITE_URI_PERMISSION
.
On Android 11 and higher, the URI access permissions give the following capabilities to the app that receives the intent:
- Read from, or write to, the data that the content URI represents, depending on the given URI permissions.
- Gain visibility into the app containing the content provider that matches the URI authority. The app that contains the content provider might be different from the app that sends the intent.
The following code snippet demonstrates how to add a URI permissions intent flag so that another app that targets Android 11 or higher can view the data in the content URI:
Kotlin
val shareIntent = Intent(Intent.ACTION_VIEW).apply { flags = Intent.FLAG_GRANT_READ_URI_PERMISSION data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP }
Java
Intent shareIntent = new Intent(Intent.ACTION_VIEW); shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);
Connect to services
If your app needs to interact with a service that isn't visible
automatically, you can declare the
appropriate intent action within a <queries>
element. The following sections
give examples using commonly-accessed services.
Connect to a text-to-speech engine
If your app interacts with a text-to-speech (TTS) engine, include the following
<intent>
element as part of the <queries>
element in your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.TTS_SERVICE" /> </intent>
Connect to a speech recognition service
If your app interacts with a speech recognition service, include the following
<intent>
element as part of the <queries>
element in your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.speech.RecognitionService" /> </intent>
Connect to media browser services
In your client media browser
app, include
the following <intent>
element as part of the <queries>
element in your
manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.media.browse.MediaBrowserService" /> </intent>
Provide custom functionality
If your needs to perform customizable actions or show customizable information
based on its interactions with other apps, you can represent that custom
behavior using intent filter
signatures as
part of the <queries>
element in your manifest. The following sections provide
more detailed guidance for several common scenarios.
Query for SMS apps
If your app needs to learn about the set of SMS apps that are installed on a
device, for example to check which app is the device's default SMS handler,
include the following <intent>
element as part of the <queries>
element in
your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SENDTO"/> <data android:scheme="smsto" android:host="*" /> </intent>
Create a custom sharesheet
Whenever possible, use a system-provided
sharesheet. Alternatively,
include the following <intent>
element as part of the <queries>
element in
your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SEND" /> <!-- Replace with the MIME type that your app works with, if needed. --> <data android:mimeType="image/jpeg" /> </intent>
The process of building the sharesheet in your app's logic, such as the call to
queryIntentActivities()
, otherwise remains unchanged compared to previous
versions of Android.
Show custom text selection actions
When users select text in your app, a text selection
toolbar
shows the set of possible operations to perform on the selected text. If this
toolbar should show custom actions from other apps, include the following
<intent>
element as part of the <queries>
element in your manifest:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.PROCESS_TEXT" /> <data android:mimeType="text/plain" /> </intent>
Show custom data rows for a contact
Apps can add custom data rows to the Contacts Provider. In order for a contacts app to show this custom data, it needs to be able to do the following:
- Read the
contacts.xml
file from the other apps. - Load an icon corresponding to the custom MIME type.
If your app is a contacts app, include the following <intent>
elements as part
of the <queries>
element in your manifest:
<!-- Place inside the <queries> element. --> <!-- Allows the app to read the "contacts.xml" file from the other apps. --> <intent> <action android:name="android.accounts.AccountAuthenticator" /> </intent> <!-- Allows the app to load an icon corresponding to the custom MIME type. --> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="content" android:host="com.android.contacts" android:mimeType="vnd.android.cursor.item/*" /> </intent>