Häufige Anwendungsfälle bei eingeschränkter Paketsichtbarkeit erfüllen

In diesem Dokument werden mehrere gängige Anwendungsfälle beschrieben, in denen eine Anwendung mit anderen Anwendungen interagiert. Jeder Abschnitt enthält eine Anleitung dazu, wie du die Funktionalität der App mit eingeschränkter Paketsichtbarkeit erreichen kannst. Dies musst du berücksichtigen, wenn deine App auf Android 11 (API-Level 30) oder höher ausgerichtet ist.

Wenn eine App, die auf Android 11 oder höher ausgerichtet ist, einen Intent verwendet, um eine Aktivität in einer anderen App zu starten, ist es am einfachsten, den Intent aufzurufen und die Ausnahme ActivityNotFoundException zu verarbeiten, wenn keine App verfügbar ist.

Wenn ein Teil Ihrer App davon abhängt, ob der Aufruf von startActivity() erfolgreich sein kann (z. B. wenn eine UI angezeigt wird), fügen Sie dem <queries>-Element des Manifests Ihrer App ein Element hinzu. In der Regel ist dies ein <intent>-Element.

URLs öffnen

In diesem Abschnitt werden verschiedene Möglichkeiten zum Öffnen von URLs in einer App beschrieben, die für Android 11 oder höher bestimmt ist.

URLs in einem Browser oder einer anderen App öffnen

Verwenden Sie zum Öffnen einer URL einen Intent, der die Intent-Aktion ACTION_VIEW enthält, wie in der Anleitung zum Laden einer Web-URL beschrieben. Nachdem Sie startActivity() mit diesem Intent aufgerufen haben, geschieht Folgendes:

  • Die URL wird in einer Webbrowser-App geöffnet.
  • Die URL wird in einer App geöffnet, die die URL als Deeplink unterstützt.
  • Ein Dialogfeld zur Auswahl wird angezeigt, in dem der Nutzer auswählen kann, mit welcher App die URL geöffnet wird.
  • Ein ActivityNotFoundException tritt auf, weil auf dem Gerät keine App installiert ist, mit der die URL geöffnet werden kann. Das ist ungewöhnlich.

    Es wird empfohlen, dass Ihre Anwendung den ActivityNotFoundException erfasst und verarbeitet, wenn er auftritt.

Da für die Methode startActivity() keine Paketsichtbarkeit erforderlich ist, um die Aktivität einer anderen App zu starten, müssen Sie dem Manifest Ihrer App kein <queries>-Element hinzufügen und auch kein vorhandenes <queries>-Element ändern. Dies gilt sowohl für implizite als auch für explizite Intents, mit denen eine URL geöffnet wird.

Verfügbarkeit eines Browsers prüfen

In einigen Fällen möchte Ihre Anwendung prüfen, ob auf dem Gerät mindestens ein Browser verfügbar ist oder ob ein bestimmter Browser der Standardbrowser ist, bevor versucht wird, eine URL zu öffnen. Füge in diesen Fällen das folgende <intent>-Element als Teil des <queries>-Elements in dein Manifest ein:

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

Wenn Sie queryIntentActivities() aufrufen und einen Web-Intent als Argument übergeben, enthält die zurückgegebene Liste in einigen Fällen die verfügbaren Browser-Apps. Die Liste enthält keine Browser-Apps, wenn der Nutzer die URL so konfiguriert hat, dass sie standardmäßig in einer Nicht-Browser-Anwendung geöffnet wird.

URLs in benutzerdefinierten Tabs öffnen

Mit benutzerdefinierten Tabs kann eine App das Erscheinungsbild des Browsers anpassen. Du kannst eine URL auf einem benutzerdefinierten Tab öffnen, ohne das <queries>-Element in deinem App-Manifest hinzufügen oder ändern zu müssen.

Du kannst aber prüfen, ob das Gerät einen Browser hat, der benutzerdefinierte Tabs unterstützt, oder mit CustomTabsClient.getPackageName() einen bestimmten Browser auswählen, um benutzerdefinierte Tabs zu starten. Füge in diesen Fällen das folgende <intent>-Element als Teil des <queries>-Elements in dein Manifest ein:

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

Verarbeitung von URLs durch Nicht-Browser-Apps zulassen

Auch wenn Ihre Anwendung URLs über benutzerdefinierte Tabs öffnen kann, sollte nach Möglichkeit eine URL auch von einer Nicht-Browser-App geöffnet werden. Um diese Funktion in Ihrer App bereitzustellen, rufen Sie startActivity() mit einem Intent auf, der das Intent-Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER festlegt. Wenn das System ein ActivityNotFoundException ausgibt, kann die App die URL in einem benutzerdefinierten Tab öffnen.

Wenn ein Intent dieses Flag enthält, bewirkt ein Aufruf von startActivity(), dass ein ActivityNotFoundException ausgelöst wird, wenn eine der folgenden Bedingungen eintritt:

  • Mit dem Aufruf wäre direkt eine Browser-App gestartet.
  • Der Aufruf hätte dem Nutzer ein Dialogfeld zur Auswahl angezeigt, in dem nur Browser-Apps verfügbar sind.

Das folgende Code-Snippet zeigt, wie Sie Ihre Logik für die Verwendung des Intent-Flags FLAG_ACTIVITY_REQUIRE_NON_BROWSER aktualisieren:

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

Dialogfeld zur Begriffsklärung vermeiden

Wenn Sie nicht möchten, dass das Dialogfeld zur Unterscheidung angezeigt wird, das Nutzer möglicherweise sehen, wenn sie eine URL öffnen, und stattdessen die URL in diesen Situationen lieber selbst verarbeiten möchten, können Sie einen Intent verwenden, der das Intent-Flag FLAG_ACTIVITY_REQUIRE_DEFAULT festlegt.

Wenn ein Intent dieses Flag enthält, bewirkt ein Aufruf von startActivity(), dass ein ActivityNotFoundException ausgelöst wird, wenn dem Nutzer durch den Aufruf ein Auswahldialogfeld angezeigt worden wäre.

Wenn ein Intent sowohl dieses Flag als auch das Intent-Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER enthält, bewirkt ein Aufruf von startActivity(), dass ein ActivityNotFoundException ausgelöst wird, wenn eine der folgenden Bedingungen eintritt:

  • Mit dem Aufruf wäre die Browser-App direkt gestartet.
  • Der Nutzer hätte beim Aufruf ein Dialogfeld zur Unterscheidung angezeigt.

Das folgende Code-Snippet zeigt, wie die Flags FLAG_ACTIVITY_REQUIRE_NON_BROWSER und FLAG_ACTIVITY_REQUIRE_DEFAULT zusammen verwendet werden:

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

Datei öffnen

Wenn Ihre App Dateien oder Anhänge verarbeitet, z. B. um zu prüfen, ob ein Gerät eine bestimmte Datei öffnen kann, ist es in der Regel am einfachsten, eine Aktivität zu starten, mit der die Datei verarbeitet werden kann. Verwenden Sie dazu einen Intent, der die Intent-Aktion ACTION_VIEW und den URI enthält, der die jeweilige Datei repräsentiert. Wenn auf dem Gerät keine App verfügbar ist, kann die App die ActivityNotFoundException erfassen. In der Logik zur Ausnahmebehandlung können Sie entweder einen Fehler anzeigen lassen oder versuchen, die Datei selbst zu verarbeiten.

Wenn für Ihre App im Voraus festgelegt werden muss, ob eine andere App eine bestimmte Datei öffnen kann, fügen Sie das Element <intent> in das folgende Code-Snippet als Teil des Elements <queries> in Ihrem Manifest ein. Geben Sie den Dateityp an, wenn Sie den Dateityp zum Zeitpunkt der Kompilierung bereits kennen.

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

Sie können dann prüfen, ob eine Anwendung verfügbar ist, indem Sie mit dem Intent resolveActivity() aufrufen.

URI-Zugriff gewähren

Hinweis:Für Apps, die auf Android 11 (API-Level 30) oder höher ausgerichtet sind, müssen die in diesem Abschnitt beschriebenen URI-Zugriffsberechtigungen deklariert werden. Es wird für alle Apps empfohlen, unabhängig von ihrer SDK-Zielversion und davon, ob ihre Contentanbieter exportiert werden.

Für Apps, die auf Android 11 oder höher ausgerichtet sind, um auf den Inhalts-URI zuzugreifen, muss der Intent der App URI-Zugriffsberechtigungen durch Festlegen eines oder beiden der folgenden Intent-Flags deklarieren: FLAG_GRANT_READ_URI_PERMISSION und FLAG_GRANT_WRITE_URI_PERMISSION.

Unter Android 11 und höher gewähren die URI-Zugriffsberechtigungen der App, die den Intent empfängt, die folgenden Funktionen:

  • Daten aus den Daten lesen oder schreiben, die der Inhalts-URI darstellt, je nach den gegebenen URI-Berechtigungen.
  • Einblick in die Anwendung mit dem Contentanbieter erhalten, der mit der URI-Zertifizierungsstelle übereinstimmt Die App, die den Contentanbieter enthält, kann sich von der App unterscheiden, die den Intent sendet.

Im folgenden Code-Snippet wird gezeigt, wie Sie ein Intent-Flag für URI-Berechtigungen hinzufügen, damit eine andere App, die auf Android 11 oder höher ausgerichtet ist, die Daten im Inhalts-URI einsehen kann:

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

Mit Diensten verbinden

Wenn Ihre App mit einem Dienst interagieren muss, der nicht automatisch sichtbar ist, können Sie die entsprechende Intent-Aktion in einem <queries>-Element deklarieren. In den folgenden Abschnitten finden Sie Beispiele für Dienste, auf die häufig zugegriffen wird.

Mit einer Sprachausgabe-Engine verbinden

Wenn Ihre App mit einer Sprachausgabe-Engine interagiert, fügen Sie das folgende <intent>-Element als Teil des <queries>-Elements in Ihr Manifest ein:

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

Mit einem Spracherkennungsdienst verbinden

Wenn Ihre Anwendung mit einem Spracherkennungsdienst interagiert, fügen Sie das folgende <intent>-Element als Teil des Elements <queries> in Ihr Manifest ein:

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

Mit Medienbrowserdiensten verbinden

Wenn Ihre App eine Clientmedien-Browser-App ist, fügen Sie das folgende <intent>-Element als Teil des <queries>-Elements in Ihr Manifest ein:

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

Benutzerdefinierte Funktionen bereitstellen

Wenn Ihre Anwendung anpassbare Aktionen ausführen oder anpassbare Informationen basierend auf ihren Interaktionen mit anderen Apps anzeigen muss, können Sie dieses benutzerdefinierte Verhalten mithilfe von Intent-Filtersignaturen als Teil des <queries>-Elements in Ihrem Manifest darstellen. In den folgenden Abschnitten finden Sie eine ausführliche Anleitung für einige gängige Szenarien.

Abfrage von SMS-Apps

Wenn Ihre App Informationen zu den auf einem Gerät installierten SMS-Apps benötigt, um beispielsweise zu prüfen, welche App der Standard-SMS-Handler des Geräts ist, fügen Sie das folgende <intent>-Element als Teil des <queries>-Elements in Ihr Manifest ein:

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

Benutzerdefiniertes Sharesheet erstellen

Verwende nach Möglichkeit ein vom System bereitgestelltes Sharesheet. Alternativ kannst du das folgende <intent>-Element als Teil des <queries>-Elements in dein Manifest einfügen:

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

Die Erstellung des Sharesheet in der App-Logik, z. B. der Aufruf von queryIntentActivities(), bleibt ansonsten unverändert im Vergleich zu Android-Versionen vor Android 11.

Benutzerdefinierte Aktionen für die Textauswahl anzeigen

Wenn Nutzer in Ihrer Anwendung Text auswählen, werden in einer Symbolleiste zur Textauswahl die möglichen Vorgänge angezeigt, die für den ausgewählten Text ausgeführt werden können. Wenn in dieser Symbolleiste benutzerdefinierte Aktionen aus anderen Apps angezeigt werden, füge deinem Manifest das folgende <intent>-Element als Teil des <queries>-Elements hinzu:

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

Benutzerdefinierte Datenzeilen für einen Kontakt anzeigen

Apps können dem Contacts Provider benutzerdefinierte Datenzeilen hinzufügen. Damit eine Kontakte-App diese benutzerdefinierten Daten anzeigen kann, müssen folgende Voraussetzungen erfüllt sein:

  1. Lies die Datei contacts.xml aus den anderen Apps.
  2. Laden Sie ein Symbol, das dem benutzerdefinierten MIME-Typ entspricht.

Wenn deine App eine Kontakte-App ist, füge deinem Manifest die folgenden <intent>-Elemente als Teil des <queries>-Elements hinzu:

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