Uprość implementację WebView dzięki Jetpack Webkit

Z tego przewodnika dowiesz się, jakie korzyści przynosi biblioteka Jetpack Webkit, jak działa i jak możesz ją wdrożyć w swoich projektach.

Przegląd

Komponenty WebView są niezbędnym elementem tworzenia aplikacji na Androida, ale czasami trudno nimi zarządzać ze względu na niespójności w funkcjach w różnych wersjach systemu operacyjnego Android. Każda wersja systemu operacyjnego Android udostępnia stały zestaw interfejsów WebView API. Ponieważ Android jest udostępniany rzadziej niż WebView, interfejsy Android API mogą nie obejmować wszystkich dostępnych funkcji WebView. Prowadzi to do wolniejszego wdrażania funkcji i zwiększenia kosztów testowania.

Jetpack Webkit rozwiązuje te problemy, działając jako warstwa zgodności i wykorzystując aktualny plik APK WebView na urządzeniu użytkownika. Zawiera też nowe i nowoczesne interfejsy API, które są dostępne tylko w tej bibliotece.

Dlaczego warto używać Jetpack Webkit?

Oprócz zapewniania zgodności między wersjami Jetpack Webkit oferuje też nowe i nowoczesne interfejsy API, które mogą uprościć tworzenie aplikacji i zwiększyć jej funkcjonalność:

  • Umożliwia nowoczesne uwierzytelnianie: WebView może bezproblemowo obsługiwać nowoczesne standardy uwierzytelniania w internecie , takie jak WebAuthn, umożliwiając logowanie za pomocą klucza dostępu. Biblioteka androidx.webkit daje pełną kontrolę nad tą integracją za pomocą metody WebSettingsCompat.setWebAuthenticationSupport(), której możesz użyć do skonfigurowania poziomu obsługi wymaganego przez Twoją aplikację.

  • Zwiększa wydajność: możesz dostroić wydajność WebView za pomocą interfejsów API, takich jak setBackForwardCacheEnabled, lub zmniejszyć opóźnienie nawigacji za pomocą spekulacyjnych interfejsów API, takich jak prefetchUrlAsync i prerenderUrlAsync. Więcej informacji znajdziesz w artykule Ładowanie spekulacyjne w komponencie WebView.

  • Zwiększa stabilność: możesz odzyskać zawieszone lub nieodpowiadające procesy renderowania bez powodowania awarii. Więcej informacji znajdziesz w artykule WebViewRenderProcess#terminate().

  • Umożliwia szczegółową kontrolę nad danymi przeglądania: aby usunąć dane przeglądania przechowywane przez WebView w przypadku określonych źródeł, użyj klasy WebStorageCompat.

  • Zwiększa wydajność stanu i pamięci: możesz bezpiecznie serializować stan nawigacji w ramach limitu transakcji wynoszącego 1 MB i uniknąć TransactionTooLargeException awarii za pomocą serializacji stanu z ograniczonym rozmiarem za pomocą WebViewCompat.saveState(). Więcej informacji znajdziesz w artykule Efektywne zarządzanie stanem WebView.

Poznaj komponenty

Aby skutecznie korzystać z Jetpack Webkit, musisz zrozumieć relacje między tymi komponentami:

  • Android System WebView: to silnik renderowania oparty na Chromium, który Google regularnie aktualizuje w Sklepie Play w tym samym tempie co Chrome. Zawiera najnowsze funkcje i kod implementacji wszystkich interfejsów WebView API.

  • Interfejsy Framework API (android.webkit): są to interfejsy API, które są powiązane z konkretną wersją systemu operacyjnego Android. Na przykład aplikacja na Androidzie 10 może mieć dostęp tylko do interfejsów API, które były dostępne w momencie wydania tej wersji. Nie może więc korzystać z nowych funkcji dodanych do pliku APK WebView w nowszych aktualizacjach. Na przykład, aby uzyskać dostęp do nieodpowiadającego renderera za pomocą WebView#getWebViewRenderProcess(), możesz wywołać tę metodę tylko w Androidzie 10 i nowszych wersjach.

  • Biblioteka Jetpack Webkit (androidx.webkit): to mała biblioteka dołączona do aplikacji. Działa ona jako pomost, który wywołuje plik APK WebView, a nie interfejsy API zdefiniowane na platformie Android, która ma stałą wersję systemu. Dzięki temu nawet jeśli aplikacja jest zainstalowana na urządzeniu z starszą wersją systemu, np. Androidem 10, może korzystać z najnowszych funkcji WebView. Na przykład, WebViewCompat.getWebViewRenderProcess() działa podobnie jak Framework API, ale można ją wywołać we wszystkich wersjach systemu starszych niż Android 10.

Jeśli interfejs API jest dostępny zarówno w platformie, jak i w Jetpack Webkit, zalecamy wybranie wersji Jetpack Webkit. Pomaga to zapewnić spójne działanie i zgodność na jak największej liczbie urządzeń.

Interakcja Jetpack Webkit i pliku APK

Interfejsy API w Jetpack Webkit są implementowane w 2 częściach:

  • Statyczny Jetpack Webkit: statyczna biblioteka Jetpack Webkit zawiera niewielką część kodu odpowiedzialnego za implementację interfejsu API.

  • Plik APK WebView: plik APK WebView zawiera większość kodu.

Twoja aplikacja wywołuje interfejs Jetpack Webkit API, który następnie wywołuje plik APK WebView.

W aplikacji możesz kontrolować wersję Jetpack Webkit, ale nie możesz kontrolować aktualizacji pliku APK WebView na urządzeniach użytkowników. Zazwyczaj większość użytkowników ma aktualne wersje pliku APK WebView, ale Twoja aplikacja musi uważać, aby nie wywoływać interfejsów API, których ta konkretna wersja pliku APK WebView nie obsługuje.

Jetpack Webkit eliminuje też konieczność ręcznego sprawdzania wersji WebView. Aby sprawdzić, czy funkcja jest dostępna, sprawdź jej stałą funkcji. Na przykład, WebViewFeature.WEB_AUTHENTICATION.

Jak to działa

Jetpack Webkit wypełnia lukę między statycznym Framework API a często aktualizowanym plikiem APK WebView. Gdy używasz interfejsu Jetpack Webkit API ze wzorcem wykrywania funkcji, biblioteka sprawdza, czy funkcja jest obsługiwana przez plik APK WebView zainstalowany na urządzeniu użytkownika. Dzięki temu nie musisz sprawdzać wersji systemu Android (frameworku).

Jeśli plik APK WebView jest wystarczająco aktualny, biblioteka wywołuje tę funkcję. W przeciwnym razie zgłasza, że funkcja jest niedostępna, co zapobiega awarii aplikacji i umożliwia eleganckie rozwiązanie tej sytuacji.

Porównanie Jetpack Webkit i Framework API

W tej sekcji porównujemy metody implementacji z biblioteką Jetpack Webkit i bez niej:

Włączanie nowoczesnego uwierzytelniania (WebAuthn)

Bez Jetpack Webkit

Nie jest to możliwe za pomocą Framework API.

Z Jetpack Webkit

Do sprawdzania zgodności używa WebViewFeature.WEB_AUTHENTICATION.

if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_AUTHENTICATION)) {
  WebSettingsCompat.setWebAuthenticationSupport(
      webView.settings,
      WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_FOR_APP
  )
}

Usuwanie danych źródła (pamięć masowa specyficzna dla witryny)

Bez Jetpack Webkit

Brak bezpośredniego interfejsu API do czyszczenia danych konkretnego źródła. Często wymaga wyczyszczenia wszystkich danych.

Z Jetpack Webkit

Do precyzyjnego usuwania danych używa interfejsów API zgodności. Możesz użyć jednej z tych opcji:

WebStorageCompat.getInstance().deleteBrowsingData()

Lub

WebStorageCompat.getInstance().deleteBrowsingDataForSite()

Pobieranie wersji WebView

Bez Jetpack Webkit

Używa standardowej klasy frameworku.

val webViewPackage = WebView.getCurrentWebViewPackage()

Z Jetpack Webkit

Do bezpieczniejszego pobierania używa warstwy zgodności.

val webViewPackage = WebViewCompat.getCurrentWebViewPackage()

Obsługa nieodpowiadającego renderera (klient renderera)

Bez Jetpack Webkit

Używa standardowej metody frameworku.

webView.setWebViewRenderProcessClient(myClient)

Z Jetpack Webkit

Do ustawiania klienta używa WebViewCompat i sprawdzania funkcji.

if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) {
  WebViewCompat.setWebViewRenderProcessClient(webView, myClient)
}

Wskazówki dotyczące wdrażania strategii odzyskiwania po awarii znajdziesz w artykule Obsługa zakończenia działania WebView WebView. Szczegółowe informacje o interfejsie API znajdziesz w androidx.webkit dokumentacji referencyjnej.

Zarządzanie zapisanym stanem i rozmiarem transakcji

Interfejs WebViewCompat.saveState API umożliwia wymuszanie limitów bajtów i przycinanie historii do przodu podczas serializacji, co zapobiega awariom TransactionTooLargeException przy jednoczesnym zachowaniu niezbędnej historii nawigacji.

Bez Jetpack Webkit

Używa standardowej metody frameworku, która serializuje cały stos nawigacji bez ograniczeń rozmiaru i może wywołać TransactionTooLargeException, jeśli ładunek przekroczy limit transakcji Androida wynoszący 1 MB.

webView.saveState(outState)

Z Jetpack Webkit

Używa WebViewCompat, aby wymusić maksymalny limit bajtów lub usunąć wpisy nawigacji do przodu, co chroni przed przepełnieniem transakcji.

WebViewCompat.saveState(webView, outState, maxSizeBytes)

Więcej informacji znajdziesz w artykule Efektywne zarządzanie stanem WebView.

Integracja Jetpack Webkit z kodem

Używanie Jetpack Webkit zwiększa możliwości standardowej klasy WebView, ale nie zastępuje jej całkowicie.

Możesz nadal używać klasy android.webkit.WebView. Możesz ją dodać do układów XML i uzyskać odniesienie do instancji w kodzie. Aby uzyskać dostęp do standardowych funkcji frameworku, możesz nadal wywoływać metody bezpośrednio w instancji WebView lub w jej obiekcie ustawień.

Aby uzyskać dostęp do nowoczesnych funkcji, użyj statycznych metod pomocniczych udostępnianych przez Jetpack Webkit, takich jak WebViewCompat i WebSettingsCompat. Do tych metod przekazujesz istniejącą instancję WebView.

Kotlin

import android.webkit.WebView
import androidx.webkit.WebSettingsCompat
import androidx.webkit.WebViewFeature

// You still get your WebView instance the standard way.
val webView: WebView = findViewById(R.id.my_webview)

// To enable a modern feature, you pass that instance to a Jetpack Webkit helper.
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
}

Java

import android.webkit.WebView;
import androidx.webkit.WebSettingsCompat;
import androidx.webkit.WebViewFeature;

// You still get your WebView instance the standard way.
WebView webView = findViewById(R.id.my_webview);

// To enable a modern feature, you pass that instance to a Jetpack Webkit helper.
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON);
}

Implementowanie Jetpack Webkit

Aby zaimplementować Jetpack Webkit, wykonaj te czynności.

Krok 1. Dodaj zależność

Aby dodać Jetpack Webkit, w pliku build.gradle.kts lub build.gradle modułu dodaj tę zależność:

Odlotowe

dependencies {
    implementation "androidx.webkit:webkit:1.17.0"
}

Kotlin

dependencies {
    implementation("androidx.webkit:webkit:1.17.0")
}

Jetpack Webkit zawiera cienkie otoki, więc wpływ na rozmiar aplikacji jest minimalny.

Krok 2. Zastosuj wzorzec wykrywania funkcji

Aby zapobiec awariom podczas wywoływania niedostępnych interfejsów API, użyj sprawdzania funkcji. Zalecamy otoczenie każdego wywołania interfejsu API sprawdzaniem funkcji i ewentualne rozważenie logiki rezerwowej na wypadek, gdy interfejs API jest niedostępny.

Zalecamy użycie tego wzorca do korzystania z nowoczesnego interfejsu WebView API:

Kotlin

import android.webkit.WebView
import androidx.webkit.WebSettingsCompat
import androidx.webkit.WebViewFeature

val webView: WebView = findViewById(R.id.my_webview)

// Before you use a modern API, first check if it is supported.
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    // If the check passes, it is safe to call the API.
    WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
} else {
    // Optionally, provide a fallback for older WebView versions.
}

Java

import android.webkit.WebView;
import androidx.webkit.WebSettingsCompat;
import androidx.webkit.WebViewFeature;

WebView webView = findViewById(R.id.my_webview);

// Before you use a modern API, first check if it is supported.
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    // If the check passes, it is safe to call the API.
    WebSettingsCompat.setForceDark(webView.getSettings(), WebSettingsCompat.FORCE_DARK_ON);
} else {
    // Optionally, provide a fallback for older WebView versions.
}

Ten wzorzec pomaga zapewnić niezawodność aplikacji. Ponieważ najpierw jest wykonywane sprawdzanie funkcji, aplikacja nie ulegnie awarii, jeśli funkcja jest niedostępna. Obciążenie wydajności związane ze sprawdzaniem WebViewFeature#isFeatureSupported() jest znikome.