Traiter des cas d'utilisation courants tout en ayant une visibilité limitée des packages

Ce document présente plusieurs cas d'utilisation courants dans lesquels une application interagit avec d'autres applications. Chaque section fournit des conseils sur le fonctionnement de l'application avec une visibilité limitée des packages. Vous devez prendre en compte cet aspect si votre application cible Android 11 (niveau d'API 30) ou une version ultérieure.

Lorsqu'une application qui cible Android 11, ou une version ultérieure, utilise un intent pour démarrer une activité dans une autre application, l'approche la plus simple consiste à appeler l'intent et à gérer l'exception ActivityNotFoundException si aucune application n'est disponible.

Si une partie de votre application nécessite de savoir si l'appel de startActivity() peut réussir (ex. : afficher une UI), ajoutez un élément à l'élément <queries> du fichier manifeste de votre application. Il s'agit généralement d'un élément <intent>.

Ouvrir des URL

Cette section décrit différentes manières d'ouvrir des URL dans une application qui cible Android 11 ou une version ultérieure.

Ouvrir des URL dans un navigateur ou une autre application

Pour ouvrir une URL, utilisez un intent contenant l'action d'intent ACTION_VIEW, comme décrit dans le guide de chargement d'une URL Web. Une fois que vous avez appelé startActivity() à l'aide de cet intent, voici ce qui se produit :

  • L'URL s'ouvre dans une application de navigateur Web.
  • L'URL s'ouvre dans une application qui l'accepte en tant que lien profond.
  • Une boîte de dialogue de sélection s'affiche, permettant à l'utilisateur de choisir l'application qui ouvre l'URL.
  • Une erreur ActivityNotFoundException se produit, car aucune application installée sur l'appareil ne peut ouvrir l'URL. (C'est inhabituel.)

    Il est recommandé que votre application intercepte et gère ActivityNotFoundException si elle se produit.

Étant donné que la méthode startActivity() ne nécessite pas de visibilité des packages pour démarrer l'activité d'une autre application, vous n'avez pas besoin d'ajouter d'élément <queries> au fichier manifeste de votre application ni de modifier un élément <queries> préexistant. Ceci s'applique aux intents implicites et explicites qui ouvrent une URL.

Vérifier si un navigateur est disponible

Dans certains cas, votre application peut vouloir vérifier qu'au moins un navigateur est disponible sur l'appareil, ou qu'un navigateur spécifique est le navigateur par défaut, avant d'essayer d'ouvrir une URL. Dans ce cas, incluez l'élément <intent> suivant dans l'élément <queries> de votre fichier manifeste :

<!-- 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>

Lorsque vous appelez queryIntentActivities() et transmettez un intent Web comme argument, la liste affichée inclut dans certains cas les applications de navigateur disponibles. La liste n'inclut pas les applications de navigateur si l'utilisateur a configuré par défaut l'URL pour qu'elle s'ouvre dans une autre application qu'un navigateur.

Ouvrir des URL dans les onglets personnalisés

Les onglets personnalisés permettent à une application de personnaliser l'apparence du navigateur. Vous pouvez ouvrir une URL dans un onglet personnalisé sans avoir à ajouter ni à modifier l'élément <queries> dans le fichier manifeste de votre application.

Toutefois, il est recommandé de vérifier si l'appareil dispose d'un navigateur compatible avec les onglets personnalisés ou de sélectionner un navigateur spécifique à lancer avec les onglets personnalisés à l'aide de CustomTabsClient.getPackageName(). Dans ce cas, incluez l'élément <intent> suivant dans l'élément <queries> de votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>

Autoriser les applications qui ne sont pas des navigateurs à gérer les URL

Même si votre application peut ouvrir des URL à l'aide d'onglets personnalisés, nous vous recommandons d'autoriser, si possible, une application autre qu'un navigateur à ouvrir une URL. Pour offrir cette possibilité à votre application, essayez d'appeler startActivity() à l'aide d'un intent qui définit l'indicateur d'intent FLAG_ACTIVITY_REQUIRE_NON_BROWSER. Si le système génère une ActivityNotFoundException, votre application peut alors ouvrir l'URL dans un onglet personnalisé.

Si un intent inclut cette option, un appel à startActivity() entraîne la génération d'une ActivityNotFoundException lorsque l'une des conditions suivantes se produit :

  • L'appel lance une application de navigateur directement.
  • L'appel propose à l'utilisateur une boîte de dialogue de sélection d'application, où les seules options sont des applications de navigateur.

L'extrait de code suivant montre comment mettre à jour votre logique pour utiliser l'indicateur d'intent FLAG_ACTIVITY_REQUIRE_NON_BROWSER :

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);
}

Éviter l'affichage d'une boîte de dialogue de sélection d'application

Si vous souhaitez éviter l'affichage d'une boîte de dialogue de sélection d'application aux utilisateurs lorsqu'ils ouvrent une URL, et si vous préférez gérer l'URL vous-même dans ces situations, vous pouvez utiliser un intent qui définit l'indicateur d'intent FLAG_ACTIVITY_REQUIRE_DEFAULT.

Si un intent inclut cette option, un appel à startActivity() entraîne la génération d'une ActivityNotFoundException lorsque l'appel aurait entraîné l'affichage d'une boîte de dialogue de sélection d'application.

Si un intent inclut à la fois cette option et l'indicateur d'intent FLAG_ACTIVITY_REQUIRE_NON_BROWSER, un appel à startActivity() entraîne la génération d'une ActivityNotFoundException lorsque l'une des conditions suivantes survient :

  • L'appel lance le navigateur directement.
  • L'appel affiche une boîte de dialogue de sélection d'application à l'utilisateur.

L'extrait de code suivant montre comment utiliser les indicateurs FLAG_ACTIVITY_REQUIRE_NON_BROWSER et FLAG_ACTIVITY_REQUIRE_DEFAULT ensemble :

Kotlin

val url = URL_TO_LOAD
try {
    // 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 {
    // 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);
}

Ouvrir un fichier

Si votre application gère des fichiers ou des pièces jointes (par exemple, si un appareil peut ouvrir un fichier donné), il est généralement plus simple de lancer une activité pouvant gérer le fichier. Pour ce faire, utilisez un intent qui inclut l'action d'intent ACTION_VIEW et l'URI qui représente le fichier spécifique. Si aucune application n'est disponible sur l'appareil, votre application peut intercepter une exception ActivityNotFoundException. Dans votre logique de gestion des exceptions, vous pouvez afficher une erreur ou essayer de gérer le fichier vous-même.

Si votre application doit savoir à l'avance si une autre application peut ouvrir un fichier donné, incluez l'élément <intent> dans l'extrait de code suivant avec l'élément <queries> de votre fichier manifeste. Incluez le type de fichier si vous savez déjà de quoi il s'agit au moment de la compilation.

<!-- 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>

Vous pouvez ensuite vérifier si une application est disponible en appelant resolveActivity() avec votre intent.

Accorder l'accès à l'URI

Remarque : La déclaration des autorisations d'accès aux URI décrite dans cette section est obligatoire pour les applications qui ciblent Android 11 (niveau d'API 30) ou une version ultérieure, et recommandée pour toutes les autres, quel que soit leur SDK cible et indépendamment du fait qu'elles exportent ou non leurs fournisseurs de contenu.

Pour accéder à l'URI de contenu, l'intent des applications qui ciblent Android 11 ou une version ultérieure doit déclarer les autorisations d'accès à l'URI en définissant au moins l'un des indicateurs d'intent suivants : FLAG_GRANT_READ_URI_PERMISSION et/ou FLAG_GRANT_WRITE_URI_PERMISSION.

Sur Android 11 et versions ultérieures, les autorisations d'accès à l'URI offrent les fonctionnalités suivantes à l'application qui reçoit l'intent :

  • Lire ou écrire dans les données représentées par l'URI de contenu, en fonction des autorisations URI données.
  • Obtenir une visibilité sur l'application contenant le fournisseur de contenu qui correspond à l'autorité de l'URI. L'application qui contient le fournisseur de contenu peut être différente de l'application qui envoie l'intent.

L'extrait de code suivant montre comment ajouter une option d'intent d'autorisations d'URI afin qu'une autre application qui cible Android 11 ou version ultérieure puisse afficher les données dans l'URI de contenu :

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);

Se connecter aux services

Si votre application doit interagir avec un service qui n'est pas visible automatiquement, vous pouvez déclarer l'action d'intent appropriée dans un élément <queries>. Les sections suivantes fournissent des exemples de services fréquemment utilisés.

Se connecter à un moteur de synthèse vocale

Si votre application interagit avec un moteur de synthèse vocale, incluez l'élément <intent> suivant dans l'élément <queries> de votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.TTS_SERVICE" />
</intent>

Se connecter à un service de reconnaissance vocale

Si votre application interagit avec un service de reconnaissance vocale, incluez l'élément <intent> suivant dans l'élément <queries> de votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.speech.RecognitionService" />
</intent>

Se connecter aux services de navigateur multimédia

Si votre application est une application de navigateur multimédia client, incluez l'élément <intent> suivant en tant que partie de l'élément <queries> dans votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.media.browse.MediaBrowserService" />
</intent>

Fournir une fonctionnalité personnalisée

Si votre application doit effectuer des actions personnalisables ou afficher des informations personnalisables en fonction de ses interactions avec d'autres applications, vous pouvez représenter ce comportement personnalisé à l'aide de signatures de filtre d'intent incluses dans l'élément <queries> dans votre fichier manifeste. Les sections suivantes fournissent des conseils détaillés pour plusieurs scénarios courants.

Requête pour les applications de SMS

Si votre application a besoin de plus d'informations sur l'ensemble d'applications de SMS installées sur un appareil (par exemple, pour identifier l'application qui est le gestionnaire de SMS par défaut de l'appareil), incluez l'élément <intent> en tant que partie de l'élément <queries> dans votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SENDTO"/>
  <data android:scheme="smsto" android:host="*" />
</intent>

Créer une Sharesheet personnalisée

Dans la mesure du possible, utilisez une Sharesheet fournie par le système. Vous pouvez également inclure l'élément <intent> suivant en tant que partie de l'élément <queries> dans votre fichier manifeste :

<!-- 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>

Le processus de création de la Sharesheet dans la logique de votre application, tel que l'appel de queryIntentActivities(), reste inchangé par rapport aux versions précédentes d'Android antérieures à Android 11.

Afficher les actions personnalisées de sélection de texte

Lorsque les utilisateurs sélectionnent du texte dans votre application, une barre d'outils de sélection de texte affiche l'ensemble des opérations possibles à effectuer sur le texte sélectionné. Si cette barre d'outils affiche des actions personnalisées provenant d'autres applications, incluez l'élément <intent> suivant en tant que partie de l'élément <queries> de votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.PROCESS_TEXT" />
  <data android:mimeType="text/plain" />
</intent>

Afficher les lignes de données personnalisées d'un contact

Les applications peuvent ajouter des lignes de données personnalisées à Contacts Provider. Pour qu'une application de contacts affiche ces données personnalisées, elle doit pouvoir effectuer les opérations suivantes :

  1. Lire le fichier contacts.xml à partir des autres applications.
  2. Charger une icône correspondant au type MIME personnalisé.

Si votre application est une application de contacts, incluez les éléments <intent> suivants en tant que partie de l'élément <queries> de votre fichier manifeste :

<!-- Place inside the <queries> element. -->
<!-- Lets the app read the contacts.xml file from other apps. -->
<intent>
  <action android:name="android.accounts.AccountAuthenticator" />
</intent>
<!-- Lets the app 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>