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

In diesem Dokument werden mehrere gängige Anwendungsfälle beschrieben, in denen eine App mit anderen Apps interagiert. In jedem Abschnitt finden Sie eine Anleitung dazu, wie Sie die Funktionen der App mit eingeschränkter Paketsichtbarkeit umsetzen können. Dies ist zu berücksichtigen, wenn Ihre 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 der einfachste Ansatz, 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. beim Anzeigen einer Benutzeroberfläche, fügen Sie dem Element <queries> im Manifest 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 auf Android 11 oder höher ausgerichtet ist.

URLs in einem Browser oder einer anderen App öffnen

Wenn Sie eine URL öffnen möchten, verwenden Sie einen Intent, der die Intent-Aktion ACTION_VIEW enthält, wie im Leitfaden 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.
  • Es wird ein Dialogfeld zur Mehrdeutigkeitsauflösung angezeigt, in dem der Nutzer auswählen kann, mit welcher App die URL geöffnet werden soll.
  • Ein ActivityNotFoundException tritt auf, weil auf dem Gerät keine App installiert ist, die die URL öffnen kann. (Das ist ungewöhnlich.)

    Es wird empfohlen, dass Ihre App die ActivityNotFoundException abfängt und verarbeitet, falls sie auftritt.

Da die Methode startActivity() keine Paketsichtbarkeit erfordert, um die Aktivität einer anderen Anwendung zu starten, müssen Sie dem Manifest Ihrer App kein <queries>-Element hinzufügen oder Änderungen an einem vorhandenen <queries>-Element vornehmen. Dies gilt sowohl für implizite als auch für explizite Intents, die eine URL öffnen.

Prüfen, ob ein Browser verfügbar ist

In einigen Fällen kann es sinnvoll sein, dass Ihre App prüft, ob mindestens ein Browser auf dem Gerät verfügbar ist oder ob ein bestimmter Browser der Standardbrowser ist, bevor sie versucht, eine URL zu öffnen. Fügen Sie in diesen Fällen 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.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-App geöffnet wird.

URLs in benutzerdefinierten Tabs öffnen

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

Sie können jedoch prüfen, ob das Gerät einen Browser hat, der benutzerdefinierte Tabs unterstützt, oder einen bestimmten Browser auswählen, der mit benutzerdefinierten Tabs gestartet werden soll. Verwenden Sie dazu CustomTabsClient.getPackageName(). 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>

URLs von anderen Apps als Browsern verarbeiten lassen

Auch wenn deine App URLs über benutzerdefinierte Tabs öffnen kann, wird empfohlen, dass du eine Nicht-Browser-App eine URL öffnen lässt, wenn möglich. Wenn du diese Funktion in deiner App anbieten möchtest, versuche, startActivity() mit einem Intent aufzurufen, der das Intent-Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER festlegt. Wenn das System eine ActivityNotFoundException ausgibt, kann Ihre App die URL in einem benutzerdefinierten Tab öffnen.

Wenn ein Intent dieses Flag enthält, wird beim Aufruf von startActivity() eine ActivityNotFoundException ausgelöst, wenn eine der folgenden Bedingungen erfüllt ist:

  • Der Aufruf hätte direkt eine Browser-App gestartet.
  • Der Aufruf hätte dem Nutzer ein Dialogfeld zur Mehrdeutigkeitsauflösung angezeigt, in dem nur Browser-Apps als Optionen verfügbar sind.

Das folgende Code-Snippet zeigt, wie Sie Ihre Logik so aktualisieren, dass das Intent-Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER verwendet wird:

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 Mehrdeutigkeitsauflösung vermeiden

Wenn Sie vermeiden möchten, dass Nutzern beim Öffnen einer URL das Dialogfeld zur Mehrdeutigkeitsauflösung angezeigt wird, und 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, wird beim Aufruf von startActivity() ein ActivityNotFoundException ausgelöst, wenn der Aufruf dem Nutzer ein Dialogfeld zur Mehrdeutigkeitsauflösung angezeigt hätte.

Wenn ein Intent sowohl dieses Flag als auch das Intent-Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER enthält, wird beim Aufruf von startActivity() ein ActivityNotFoundException ausgelöst, wenn eine der folgenden Bedingungen erfüllt ist:

  • Der Aufruf hätte die Browser-App direkt gestartet.
  • Der Aufruf hätte dem Nutzer ein Dialogfeld zur Mehrdeutigkeitsauflösung 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 deine App Dateien oder Anhänge verarbeitet, z. B. prüft, ob ein Gerät eine bestimmte Datei öffnen kann, ist es in der Regel am einfachsten, eine Aktivität zu starten, die die Datei verarbeiten kann. Verwenden Sie dazu einen Intent, der die Intent-Aktion ACTION_VIEW und den URI enthält, der die jeweilige Datei darstellt. Wenn auf dem Gerät keine App verfügbar ist, kann Ihre App die ActivityNotFoundException abfangen. In der Logik zur Ausnahmebehandlung können Sie entweder einen Fehler anzeigen oder versuchen, die Datei selbst zu verarbeiten.

Wenn Ihre App im Voraus wissen muss, ob eine andere App eine bestimmte Datei öffnen kann, fügen Sie das Element <intent> im folgenden Code-Snippet als Teil des Elements <queries> in Ihr Manifest ein. Geben Sie den Dateityp an, wenn Sie ihn bereits zur Kompilierungszeit 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>

Anschließend können Sie prüfen, ob eine App verfügbar ist, indem Sie resolveActivity() mit Ihrem Intent aufrufen.

URI-Zugriff gewähren

Hinweis:Die Deklaration von URI-Zugriffsberechtigungen, wie in diesem Abschnitt beschrieben, ist für Apps erforderlich, die auf Android 11 (API-Level 30) oder höher ausgerichtet sind. Sie wird für alle Apps empfohlen, unabhängig von der Ziel-SDK-Version und davon, ob sie ihre Contentanbieter exportieren.

Damit Apps, die auf Android 11 oder höher ausgerichtet sind, auf den Inhalts-URI zugreifen können, müssen im Intent Ihrer App URI-Zugriffsberechtigungen deklariert werden. Dazu müssen Sie eines oder beide der folgenden Intent-Flags festlegen: FLAG_GRANT_READ_URI_PERMISSION und FLAG_GRANT_WRITE_URI_PERMISSION.

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

  • Daten, die der Inhalts-URI darstellt, je nach den angegebenen URI-Berechtigungen lesen oder schreiben.
  • Sie erhalten Einblick in die App, die den Contentanbieter enthält, der mit der URI-Autorität übereinstimmt. Die App, die den Contentanbieter enthält, kann sich von der App unterscheiden, die den Intent sendet.

Das folgende Code-Snippet zeigt, 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 aufrufen 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);

Verbindung zu Diensten herstellen

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 häufig verwendete Dienste.

Verbindung zu einer Text-zu-Sprache-Engine herstellen

Wenn deine App mit einer Text-zu-Sprache-Engine (TTS) interagiert, füge 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.TTS_SERVICE" />
</intent>

Verbindung zu einem Spracherkennungsdienst herstellen

Wenn Ihre App mit einem Spracherkennungsdienst 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.speech.RecognitionService" />
</intent>

Verbindung zu Medienbrowser-Diensten herstellen

Wenn deine App eine Client-Mediabrowser-App ist, füge das folgende <intent>-Element als Teil des <queries>-Elements in dein Manifest ein:

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

Benutzerdefinierte Funktionen bereitstellen

Wenn deine App anpassbare Aktionen ausführen oder anpassbare Informationen basierend auf ihren Interaktionen mit anderen Apps anzeigen muss, kannst du dieses benutzerdefinierte Verhalten mithilfe von Intent-Filtersignaturen als Teil des <queries>-Elements in deinem Manifest darstellen. In den folgenden Abschnitten finden Sie detaillierte Anleitungen für mehrere gängige Szenarien.

SMS-Apps abfragen

Wenn deine App Informationen zu den auf einem Gerät installierten SMS-Apps benötigt, z. B. um zu prüfen, welche App der Standard-SMS-Handler des Geräts ist, füge 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.SENDTO"/>
  <data android:scheme="smsto" android:host="*" />
</intent>

Benutzerdefiniertes Sharesheet erstellen

Verwenden Sie nach Möglichkeit ein vom System bereitgestelltes Sharesheet. Alternativ können Sie das folgende <intent>-Element als Teil des <queries>-Elements in Ihr 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>

Der Prozess zum Erstellen des Sharesheets in der Logik Ihrer App, z. B. der Aufruf von queryIntentActivities(), bleibt im Vergleich zu Android-Versionen vor Android 11 unverändert.

Benutzerdefinierte Aktionen für die Textauswahl anzeigen

Wenn Nutzer Text in Ihrer App auswählen, wird in einer Symbolleiste für die Textauswahl eine Reihe möglicher 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ü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.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, muss sie Folgendes tun können:

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

Wenn es sich bei Ihrer App um eine Kontakte-App handelt, fügen Sie die folgenden <intent>-Elemente als Teil des <queries>-Elements in Ihr Manifest ein:

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