Android 11 hat Änderungen an der Interaktion von Apps mit anderen Apps vorgenommen, die der Nutzer auf dem Gerät installiert hat. Weitere Informationen zu diesen Änderungen finden Sie in der Android-Dokumentation.
Wenn eine Android-App mit benutzerdefinierten Tabs auf SDK-Level 30 oder höher ausgerichtet ist, sind möglicherweise einige Änderungen erforderlich. In diesem Artikel werden die Änderungen beschrieben, die für diese Apps möglicherweise erforderlich sind.
Im einfachsten Fall können benutzerdefinierte Tabs mit einem One-Liner wie diesem gestartet werden:
new CustomTabsIntent.Builder().build()
.launchUrl(this, Uri.parse("https://www.example.com"));
Bei Anwendungen, die mit diesem Ansatz gestartet werden oder bei denen die Benutzeroberfläche angepasst wird, z. B. durch Ändern der Symbolleistenart oder Hinzufügen einer Aktionsschaltfläche, müssen keine Änderungen an der Anwendung vorgenommen werden.
Bevorzugung systemeigener Apps
Wenn Sie jedoch die Best Practices befolgt haben, sind möglicherweise einige Änderungen erforderlich.
Die erste relevante Best Practice ist, dass Anwendungen bevorzugt eine native App zum Bearbeiten des Intents verwenden sollten, anstatt einen benutzerdefinierten Tab, wenn eine App installiert ist, die den Intent verarbeiten kann.
Android 11 und höher
In Android 11 wird ein neues Intent-Flag eingeführt: FLAG_ACTIVITY_REQUIRE_NON_BROWSER
. Dies ist die empfohlene Methode zum Öffnen einer nativen App, da die App keine Paketmanagerabfragen deklarieren muss.
static boolean launchNativeApi30(Context context, Uri uri) {
Intent nativeAppIntent = new Intent(Intent.ACTION_VIEW, uri)
.addCategory(Intent.CATEGORY_BROWSABLE)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
try {
context.startActivity(nativeAppIntent);
return true;
} catch (ActivityNotFoundException ex) {
return false;
}
}
Die Lösung besteht darin, den Intent zu starten und Android über FLAG_ACTIVITY_REQUIRE_NON_BROWSER
zu bitten, beim Starten keine Browser zu verwenden.
Wenn keine native App gefunden wird, die diesen Intent bearbeiten kann, wird eine ActivityNotFoundException
geworfen.
Vor Android 11
Auch wenn die Anwendung auf Android 11 oder API-Level 30 ausgerichtet ist, wird das Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER
von früheren Android-Versionen nicht unterstützt. In diesen Fällen müssen wir den Paketmanager abfragen:
private static boolean launchNativeBeforeApi30(Context context, Uri uri) {
PackageManager pm = context.getPackageManager();
// Get all Apps that resolve a generic url
Intent browserActivityIntent = new Intent()
.setAction(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setData(Uri.fromParts("http", "", null));
Set<String> genericResolvedList = extractPackageNames(
pm.queryIntentActivities(browserActivityIntent, 0));
// Get all apps that resolve the specific Url
Intent specializedActivityIntent = new Intent(Intent.ACTION_VIEW, uri)
.addCategory(Intent.CATEGORY_BROWSABLE);
Set<String> resolvedSpecializedList = extractPackageNames(
pm.queryIntentActivities(specializedActivityIntent, 0));
// Keep only the Urls that resolve the specific, but not the generic
// urls.
resolvedSpecializedList.removeAll(genericResolvedList);
// If the list is empty, no native app handlers were found.
if (resolvedSpecializedList.isEmpty()) {
return false;
}
// We found native handlers. Launch the Intent.
specializedActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(specializedActivityIntent);
return true;
}
Dabei wird der Paketmanager nach Anwendungen abgefragt, die eine generische http
-Intent unterstützen. Das sind wahrscheinlich Browser.
Anschließend werden Anwendungen abgefragt, die Inhalte für die URL verarbeiten, die wir starten möchten. Es werden sowohl Browser als auch native Anwendungen zurückgegeben, die für die Verarbeitung dieser URL eingerichtet sind.
Entfernen Sie nun alle Browser aus der ersten Liste aus der zweiten Liste. Es bleiben nur native Apps übrig.
Wenn die Liste leer ist, wissen wir, dass es keine nativen Handler gibt, und geben „false“ zurück. Andernfalls wird die Intent für den nativen Handler gestartet.
Zusammenfassung
Wir müssen dafür sorgen, dass für jeden Fall die richtige Methode verwendet wird:
static void launchUri(Context context, Uri uri) {
boolean launched = Build.VERSION.SDK_INT >= 30 ?
launchNativeApi30(context, uri) :
launchNativeBeforeApi30(context, uri);
if (!launched) {
new CustomTabsIntent.Builder()
.build()
.launchUrl(context, uri);
}
}
Build.VERSION.SDK_INT
enthält die erforderlichen Informationen. Wenn der Wert 30 oder höher ist, kennt Android die FLAG_ACTIVITY_REQUIRE_NON_BROWSER
und wir können versuchen, eine native App mit dem neuen Ansatz zu starten. Andernfalls versuchen wir, die Einführung mit dem alten Ansatz durchzuführen.
Wenn das Starten einer nativen App fehlschlägt, werden benutzerdefinierte Tabs gestartet.
Diese Best Practice umfasst einige Standardelemente. Wir arbeiten daran, dies zu vereinfachen, indem wir die Komplexität in einer Bibliothek kapseln. Wir halten Sie über Updates der Supportbibliothek android-browser-helper auf dem Laufenden.
Browser erkennen, die benutzerdefinierte Tabs unterstützen
Ein weiteres gängiges Muster ist die Verwendung des PackageManagers, um festzustellen, welche Browser benutzerdefinierte Tabs auf dem Gerät unterstützen. Gängige Anwendungsfälle hierfür sind das Festlegen des Pakets für den Intent, um das Dialogfeld zur App-Entfernung zu vermeiden, oder die Auswahl des Browsers, mit dem eine Verbindung zum Custom Tabs-Dienst hergestellt werden soll.
Wenn das Targeting auf API-Level 30 erfolgt, müssen Entwickler ihrem Android-Manifest einen Bereich für Abfragen hinzufügen und einen Intent-Filter deklarieren, der Browser mit Unterstützung für benutzerdefinierte Tabs abgleicht.
<queries>
<intent>
<action android:name=
"android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
Wenn das Markup vorhanden ist, funktioniert der vorhandene Code, der zum Abfragen von Browsern verwendet wird, die benutzerdefinierte Tabs unterstützen, wie erwartet.
Häufig gestellte Fragen
Frage: Der Code, der nach Anbietern von benutzerdefinierten Tabs sucht, sucht nach Anwendungen, die https://
-Intents verarbeiten können, der Abfragefilter deklariert jedoch nur eine android.support.customtabs.action.CustomTabsService
-Abfrage. Sollte nicht eine Abfrage für https://
-Intents deklariert werden?
A: Wenn Sie einen Abfragefilter deklarieren, werden die Antworten auf eine Abfrage an den PackageManager gefiltert, nicht die Abfrage selbst. Da Browser, die benutzerdefinierte Tabs unterstützen, angeben, dass sie den CustomTabsService verarbeiten, werden sie nicht herausgefiltert. Browser, die benutzerdefinierte Tabs nicht unterstützen, werden herausgefiltert.
Fazit
Das sind alle Änderungen, die erforderlich sind, um eine vorhandene Custom Tabs-Integration für Android 11 anzupassen. Weitere Informationen zur Einbindung von Custom Tabs in eine Android-App finden Sie im Implementierungsleitfaden und in den Best Practices für eine erstklassige Integration.
Bei Fragen oder Feedback kannst du dich jederzeit gern an uns wenden.