Ein vollständiges Beispiel finden Sie in der GitHub-Beispielanwendung. Es enthält wiederverwendbare Klassen zum Anpassen der Benutzeroberfläche, zum Herstellen einer Verbindung zum Hintergrunddienst und zum Verwalten des Lebenszyklus der Anwendung und der benutzerdefinierten Registerkartenaktivität.
Wenn Sie den Anweisungen auf dieser Seite folgen, können Sie eine großartige Integration erstellen.
Der erste Schritt für eine benutzerdefinierte Tabs-Integration ist das Hinzufügen der AndroidX-Browserbibliothek zu Ihrem Projekt. Öffnen Sie die Datei app/build.gradle
und fügen Sie die Browserbibliothek zum Abschnitt Abhängigkeiten hinzu.
dependencies {
...
implementation "androidx.browser:browser:1.3.0"
}
Sobald die Browserbibliothek zu Ihrem Projekt hinzugefügt wurde, gibt es zwei mögliche Anpassungen:
- Anpassen der Benutzeroberfläche und Interaktion mit den benutzerdefinierten Registerkarten.
- Die Seite schneller laden und die Anwendung am Leben erhalten.
Die UI-Anpassungen werden mit den Klassen CustomTabsIntent
und CustomTabsIntent.Builder
vorgenommen; die Leistungsverbesserungen werden erreicht, indem CustomTabsClient
verwendet wird, um eine Verbindung zum Dienst für benutzerdefinierte Registerkarten herzustellen, den Browser aufzuwärmen und ihm mitzuteilen, welche URLs geöffnet werden.
Öffnen einer benutzerdefinierten Registerkarte #
A CustomTabsIntent.Builder
kann verwendet werden, um eine benutzerdefinierte Registerkarte zu konfigurieren. Sobald Sie fertig sind, rufen Sie CustomTabsIntent.Builder.build
auf, um eine CustomTabsIntent
und starten Sie die gewünschte URL mit CustomTabsIntent.launchUrl
.
String url = ¨https://paul.kinlan.me/¨;
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse(url));
Konfigurieren der Farbe der Adressleiste #
Einer der wichtigsten (und am einfachsten zu implementierenden) Aspekte von benutzerdefinierten Registerkarten ist die Möglichkeit, die Farbe der Adressleiste so zu ändern, dass sie mit dem Thema Ihrer App übereinstimmt.
Das folgende Snippet ändert die Hintergrundfarbe für die Adressleiste. colorInt ist ein int, das eine Color
angibt.
int coolorInt = Color.parseColor("#FF0000"); //red
builder.setToolbarColor(colorInt);
Konfigurieren Sie eine benutzerdefinierte Aktionsschaltfläche #
builder.setActionButton(icon, description, pendingIntent, tint);
Als Entwickler Ihrer App haben Sie die volle Kontrolle über die Aktionsschaltfläche, die Ihren Benutzern auf der Browser-Registerkarte angezeigt wird.
In den meisten Fällen handelt es sich dabei um eine primäre Aktion wie Freigeben oder eine andere gemeinsame Aktivität, die Ihre Benutzer ausführen.
Die Aktionsschaltfläche wird als Bundle mit einem Symbol der Aktionsschaltfläche und einer PendingIntent
dargestellt, die vom Browser aufgerufen wird, wenn Ihr Benutzer auf die Aktionsschaltfläche klickt. Das Symbol ist currenlty 24dp in der Höhe und 24-48 dp in der Breite.
Es kann durch Aufrufen von CustomTabsIntentBuilder#setActionButton
angepasst werden:
-
icon
ist einBitmap
als Bildquelle für die Aktionsschaltfläche verwendet werden. -
description
ist einString
als zugängliche Beschreibung für die Schaltfläche verwendet werden. -
pendingIntent
ist einePendingIntent
, die gestartet werden soll, wenn auf die Aktionsschaltfläche oder den Menüpunkt getippt wurde. Der Browser ruft beim TippenPendingIntent#send
auf, nachdem die URL als Daten hinzugefügt wurde. Die Client-App kannIntent#getDataString
aufrufen, um die URL abzurufen. -
tint
ist ein boolescher Wert, der definiert, ob die Aktionsschaltfläche getönt werden soll.
Benutzerdefiniertes Menü konfigurieren #
builder.addMenuItem(menuItemTitle, menuItemPendingIntent);
Der Browser verfügt über ein umfassendes Menü mit Aktionen, die Benutzer häufig in einem Browser ausführen, die jedoch für Ihren Anwendungskontext möglicherweise nicht relevant sind.
Benutzerdefinierte Registerkarten verfügen über eine Reihe von Standardaktionen, die vom Browser bereitgestellt werden. Diese Aktionen können Elemente wie „Weiterleiten“, „Seiteninfo“, „Aktualisieren“, „In Seite suchen“ oder „Im Browser öffnen“ enthalten.
Als Entwickler können Sie bis zu fünf Menüelemente hinzufügen und anpassen, die zwischen der Symbolzeile und den Fußelementen angezeigt werden.
Ein Menüpunkt wird hinzugefügt, indem CustomTabsIntent.Builder#addMenuItem
mit Titel und PendingIntent
aufgerufen wird, den der Browser in Ihrem Namen aufruft, wenn der Benutzer auf das Element tippt.
Konfigurieren benutzerdefinierter Ein- und Ausstiegsanimationen #
Viele Android-Anwendungen verwenden beim Übergang zwischen Aktivitäten unter Android benutzerdefinierte Ein- und Ausstiegsanimationen. Benutzerdefinierte Registerkarten ist nicht anders, können Sie den Eingang und Ausgang (wenn der Benutzer drückt zurück) Animationen ändern, um sie im Einklang mit dem Rest der Anwendung zu halten.
builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left);
builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);
Wärmen Sie den Browser auf, damit Seiten schneller geladen werden #
Wenn CustomTabsIntent#launchUrl
aufgerufen wird, wird standardmäßig der Browser hochgefahren und die URL gestartet. Dies kann wertvolle Zeit in Anspruch nehmen und die Wahrnehmung von Glätte beeinträchtigen.Daher haben wir einen Dienst bereitgestellt, mit dem Ihre App eine Verbindung herstellen und den Browser und seine nativen Komponenten auffordern kann, sich aufzuwärmen. Benutzerdefinierte Registerkarten bieten Ihnen als Entwickler auch die Möglichkeit, dem Browser mitzuteilen, welche Webseiten der Benutzer wahrscheinlich besuchen wird. Browser können dann Folgendes ausführen:
- DNS-Vorauflösung der Hauptdomäne
- DNS-Vorauflösung der wahrscheinlichsten Unterressourcen
- Vorverbindung zum Ziel einschließlich HTTPS / TLS-Aushandlung.
Der Vorgang zum Aufwärmen des Browsers ist wie folgt:
- Verwenden Sie
CustomTabsClient#bindCustomTabsService
, um eine Verbindung zum Dienst herzustellen. - Sobald der Dienst verbunden ist, rufen Sie
CustomTabsClient#warmup
auf, um den Browser hinter den Kulissen zu starten. - Rufen Sie
CustomTabsClient#newSession
auf, um eine neue Sitzung zu erstellen. Diese Sitzung wird für alle Anfragen an die API verwendet. - Fügen Sie optional beim Erstellen einer neuen Sitzung einen
CustomTabsCallback
als Parameter hinzu, damit Sie wissen, dass eine Seite geladen wurde. - Teilen Sie dem Browser mit, welche Seiten der Benutzer wahrscheinlich laden wird, mit
CustomTabsSession#mayLaunchUrl
- Rufen Sie den
CustomTabsIntent.Builder
Konstruktor auf und übergeben Sie den erstelltenCustomTabsSession
als Parameter.
Verbindung zum Dienst für benutzerdefinierte Registerkarten herstellen #
Die CustomTabsClient#bindCustomTabsService
-Methode vereinfacht die Verbindung zum Dienst für benutzerdefinierte Registerkarten.
Erstellen Sie eine Klasse, die CustomTabsServiceConnection
erweitert, und verwenden Sie onCustomTabsServiceConnected
, um eine Instanz von CustomTabsClient
. Diese Instanz wird für die nächsten Schritte benötigt.
// Package name for the Chrome channel the client wants to connect to. This
// depends on the channel name.
// Stable = com.android.chrome
// Beta = com.chrome.beta
// Dev = com.chrome.dev
public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
mCustomTabsClient = client;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
boolean ok = CustomTabsClient.bindCustomTabsService(this, mPackageNameToBind, connection);
Aufwärmen des Browserprozesses #
boolean warmup(long flags)
Erwärmt den Browserprozess und lädt die nativen Bibliotheken. Warmup ist asynchron, der Rückgabewert gibt an, ob die Anforderung akzeptiert wurde. Mehrere erfolgreiche Aufrufe geben ebenfalls true zurück.
Gibt bei Erfolg true
zurück.
Erstellen Sie eine neue Registerkarte session #
boolean newSession(CustomTabsCallback callback)
Session wird in nachfolgenden Aufrufen verwendet, um mayLaunchUrl Aufruf, den CustomTabsIntent und die Registerkarte miteinander zu verknüpfen. Der hier bereitgestellte Rückruf ist der erstellten Sitzung zugeordnet. Alle Aktualisierungen für die erstellte Sitzung (siehe Rückruf für benutzerdefinierte Registerkarten unten) werden ebenfalls über diesen Rückruf empfangen. Gibt zurück, ob eine Sitzung erfolgreich erstellt wurde. Mehrere Aufrufe mit demselben CustomTabsCallback oder einem Nullwert geben false zurück.
Teilen Sie dem Browser mit, welche URLs der Benutzer wahrscheinlich öffnen wird #
boolean mayLaunchUrl(Uri url, Bundle extras, List<Bundle> otherLikelyBundles)
Diese CustomTabsSession-Methode teilt dem Browser eine wahrscheinliche zukünftige Navigation zu einer URL mit. Die Methode warmup()
sollte zuerst als Best Practice aufgerufen werden. Die wahrscheinlichste URL muss zuerst angegeben werden. Optional kann eine Liste anderer wahrscheinlicher URLs bereitgestellt werden. Sie werden als weniger wahrscheinlich als die erste behandelt und müssen in absteigender Prioritätsreihenfolge sortiert werden. Diese zusätzlichen URLs können ignoriert werden. Alle vorherigen Aufrufe dieser Methode werden priorisiert. Gibt zurück, ob der Vorgang erfolgreich abgeschlossen wurde.
Verbindungsrückruf für benutzerdefinierte Registerkarten #
void onNavigationEvent(int navigationEvent, Bundle extras)
Wird aufgerufen, wenn ein Navigationsereignis in der benutzerdefinierten Registerkarte auftritt. Die navigationEvent int
ist einer von 6 Werten, die den Zustand der Seite definiert, ist in. Weitere Informationen finden Sie unten.
/**
* Sent when the tab has started loading a page.
*/
public static final int NAVIGATION_STARTED = 1;
/**
* Sent when the tab has finished loading a page.
*/
public static final int NAVIGATION_FINISHED = 2;
/**
* Sent when the tab couldn't finish loading due to a failure.
*/
public static final int NAVIGATION_FAILED = 3;
/**
* Sent when loading was aborted by a user action before it finishes like clicking on a link
* or refreshing the page.
*/
public static final int NAVIGATION_ABORTED = 4;
/**
* Sent when the tab becomes visible.
*/
public static final int TAB_SHOWN = 5;
/**
* Sent when the tab becomes hidden.
*/
public static final int TAB_HIDDEN = 6;
Was passiert, wenn der Benutzer keinen Browser installiert hat, der benutzerdefinierte Registerkarten unterstützt? #
Custom Tabs wird von den meisten Android-Browsern unterstützt. Da es jedoch eine ACTION_VIEW
-Absicht mit wichtigen Extras zum Anpassen der Benutzeroberfläche verwendet, wird es im Systembrowser oder im Standardbrowser des Benutzers geöffnet, wenn benutzerdefinierte Registerkarten nicht unterstützt werden.
Wenn der Benutzer einen Browser installiert hat, der benutzerdefinierte Registerkarten unterstützt, und es sich um den Standardbrowser handelt, werden die EXTRAS automatisch abgerufen und eine benutzerdefinierte Benutzeroberfläche angezeigt.
Wie kann ich überprüfen, ob das Android-Gerät über einen Browser verfügt, der benutzerdefinierte Registerkarten unterstützt? #
Es ist möglich, PackageManager
zu verwenden, um das Android-Gerät nach Anwendungen abzufragen, die benutzerdefinierte Registerkarten verarbeiten können. Wir fragen nach Anwendungen ab, die http
Absichten verarbeiten können, und prüfen dann, ob diese Anwendungen auch die Unterstützung für den Dienst für benutzerdefinierte Registerkarten deklarieren:
/**
* Returns a list of packages that support Custom Tabs.
*/
public static ArrayList<ResolveInfo> getCustomTabsPackages(Context context) {
PackageManager pm = context.getPackageManager();
// Get default VIEW intent handler.
Intent activityIntent = new Intent()
.setAction(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setData(Uri.fromParts("http", "", null));
// Get all apps that can handle VIEW intents.
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
ArrayList<ResolveInfo> packagesSupportingCustomTabs = new ArrayList<>();
for (ResolveInfo info : resolvedActivityList) {
Intent serviceIntent = new Intent();
serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
serviceIntent.setPackage(info.activityInfo.packageName);
// Check if this package also resolves the Custom Tabs service.
if (pm.resolveService(serviceIntent, 0) != null) {
packagesSupportingCustomTabs.add(info);
}
}
return packagesSupportingCustomTabs;
}
Android 11 hat Änderungen an der Sichtbarkeit von Paketen eingeführt. Wenn Ihre Android-App auf API-Level 30 oder höher abzielt, ist das Hinzufügen eines queries
-Abschnitts zu AndroidManifest.xml
erforderlich, andernfalls gibt das obige Code-Snippet keine Ergebnisse zurück:
<queries>
<intent>
<action android:name=
"android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>