Android udostępnia kilka interfejsów API, które pomagają zarządzać obiektami wyświetlającymi treści internetowe w aplikacji.WebView
Na tej stronie opisujemy, jak używać tych interfejsów API do efektywniejszego korzystania z WebViewobiektów, co zwiększa stabilność i bezpieczeństwo aplikacji.
Version API
Począwszy od Androida 7.0 (interfejs API na poziomie 24), użytkownicy mogą wybierać spośród kilku różnych pakietów do wyświetlania treści internetowych w obiekcie WebView.
Biblioteka Jetpack Webkit zawiera metodę getCurrentWebViewPackage(), która służy do pobierania informacji związanych z pakietem wyświetlającym treści internetowe w aplikacji. Ta metoda jest przydatna podczas analizowania błędów, które występują tylko wtedy, gdy aplikacja próbuje wyświetlić treści internetowe za pomocą implementacji WebView w określonym pakiecie.
Aby użyć tej metody, dodaj logikę pokazaną w tym fragmencie kodu:
Kotlin
val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext) Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")
Java
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext); Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
Usługa Bezpieczne przeglądanie Google
Aby zapewnić użytkownikom bezpieczniejsze przeglądanie, WebViewobiekty weryfikują adresy URL za pomocą Bezpiecznego przeglądania Google. Dzięki temu aplikacja może wyświetlać ostrzeżenie, gdy użytkownicy próbują przejść do potencjalnie niebezpiecznej witryny.
Chociaż domyślna wartość EnableSafeBrowsing to „true”, w niektórych przypadkach możesz chcieć włączyć Bezpieczne przeglądanie tylko warunkowo lub je wyłączyć. Android 8.0 (API na poziomie 26) i nowsze wersje obsługują używanie setSafeBrowsingEnabled() do przełączania Bezpiecznego przeglądania dla poszczególnych obiektów WebView.
Jeśli chcesz, aby wszystkie obiekty WebView nie były sprawdzane przez Bezpieczne przeglądanie, dodaj do pliku manifestu aplikacji ten element <meta-data>:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
Definiowanie działań automatyzacji
Gdy instancja WebView próbuje załadować stronę, która jest przez Google klasyfikowana jako znane zagrożenie, domyślnie wyświetla stronę pełnoekranową z ostrzeżeniem o tym zagrożeniu. Na tym ekranie użytkownicy mogą załadować adres URL lub wrócić do poprzedniej, bezpiecznej strony.WebView
Jeśli Twoja aplikacja jest kierowana na Androida 8.1 (poziom interfejsu API 27) lub nowszego, możesz programowo określić, jak ma reagować na znane zagrożenie, w ten sposób:
- Możesz określić, czy Twoja aplikacja ma zgłaszać znane zagrożenia do Bezpiecznego przeglądania.
- Możesz skonfigurować aplikację tak, aby automatycznie wykonywała określone działanie, np. wracała do bezpiecznego stanu, za każdym razem, gdy napotka adres URL sklasyfikowany jako znane zagrożenie.
Poniższe fragmenty kodu pokazują, jak poinstruować instancje aplikacji WebView, aby po napotkaniu znanego zagrożenia zawsze wracały do bezpiecznego stanu:
MyWebActivity.java
Kotlin
private lateinit var superSafeWebView: WebView private var safeBrowsingIsInitialized: Boolean = false // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) superSafeWebView = WebView(this) superSafeWebView.webViewClient = MyWebViewClient() safeBrowsingIsInitialized = false if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, ValueCallback<Boolean> { success -> safeBrowsingIsInitialized = true if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!") } }) } }
Java
private WebView superSafeWebView; private boolean safeBrowsingIsInitialized; // ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); superSafeWebView = new WebView(this); superSafeWebView.setWebViewClient(new MyWebViewClient()); safeBrowsingIsInitialized = false; if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, new ValueCallback<Boolean>() { @Override public void onReceiveValue(Boolean success) { safeBrowsingIsInitialized = true; if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!"); } } }); } }
MyWebViewClient.java
Kotlin
class MyWebViewClient : WebViewClientCompat() { // Automatically go "back to safety" when attempting to load a website that // Google identifies as a known threat. An instance of WebView calls this // method only after Safe Browsing is initialized, so there's no conditional // logic needed here. override fun onSafeBrowsingHit( view: WebView, request: WebResourceRequest, threatType: Int, callback: SafeBrowsingResponseCompat ) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true) Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show() } } }
Java
public class MyWebViewClient extends WebViewClientCompat { // Automatically go "back to safety" when attempting to load a website that // Google identifies as a known threat. An instance of WebView calls this // method only after Safe Browsing is initialized, so there's no conditional // logic needed here. @Override public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponseCompat callback) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true); Toast.makeText(view.getContext(), "Unsafe web page blocked.", Toast.LENGTH_LONG).show(); } } }
HTML5 Geolocation API
W przypadku aplikacji kierowanych na Androida 6.0 (poziom interfejsu API 23) i nowsze wersje interfejs Geolocation API jest obsługiwany tylko w bezpiecznych źródłach, takich jak HTTPS. Wszelkie żądania wysyłane do interfejsu Geolocation API ze źródeł niezabezpieczonych są automatycznie odrzucane bez wywoływania odpowiedniej metody onGeolocationPermissionsShowPrompt().
Rezygnacja ze zbierania danych
WebView może przesyłać do Google anonimowe dane diagnostyczne, gdy użytkownik wyrazi na to zgodę. Dane są zbierane w przypadku każdej aplikacji, która tworzy instancję WebView. Możesz zrezygnować z tej funkcji, tworząc w elemencie <application> manifestu ten tag:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
Dane są przesyłane z aplikacji tylko wtedy, gdy użytkownik wyrazi na to zgodę i aplikacja nie zrezygnuje z tej funkcji. Więcej informacji o rezygnowaniu z przesyłania danych diagnostycznych znajdziesz w artykule Prywatność użytkowników w raportowaniu WebView.
Termination Handling API
Interfejs Termination Handling API obsługuje przypadki, w których proces renderowania obiektuWebViewzostaje zakończony, ponieważ system zamyka go, aby odzyskać niezbędną pamięć, lub z powodu awarii. Korzystając z tego interfejsu API, możesz zezwolić aplikacji na dalsze działanie, nawet jeśli proces renderowania zostanie zakończony.
Jeśli podczas wczytywania określonej strony internetowej proces renderowania ulegnie awarii, ponowna próba wczytania tej samej strony może spowodować, że nowy obiekt WebView będzie wykazywać to samo zachowanie awarii renderowania.
Poniższy fragment kodu pokazuje, jak używać tego interfejsu API w Activity:
Kotlin
inner class MyRendererTrackingWebViewClient : WebViewClient() { private var mWebView: WebView? = null override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean { if (!detail.didCrash()) { // Renderer is killed because the system ran out of memory. The app // can recover gracefully by creating a new WebView instance in the // foreground. Log.e("MY_APP_TAG", ("System killed the WebView rendering process " + "to reclaim memory. Recreating...")) mWebView?.also { webView -> val webViewContainer: ViewGroup = findViewById(R.id.my_web_view_container) webViewContainer.removeView(webView) webView.destroy() mWebView = null } // By this point, the instance variable "mWebView" is guaranteed to // be null, so it's safe to reinitialize it. return true // The app continues executing. } // Renderer crashes because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!") // In this example, the app itself crashes after detecting that the // renderer crashed. If you handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false } }
Java
public class MyRendererTrackingWebViewClient extends WebViewClient { private WebView mWebView; @Override public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { if (!detail.didCrash()) { // Renderer is killed because the system ran out of memory. The app // can recover gracefully by creating a new WebView instance in the // foreground. Log.e("MY_APP_TAG", "System killed the WebView rendering process " + "to reclaim memory. Recreating..."); if (mWebView != null) { ViewGroup webViewContainer = (ViewGroup) findViewById(R.id.my_web_view_container); webViewContainer.removeView(mWebView); mWebView.destroy(); mWebView = null; } // By this point, the instance variable "mWebView" is guaranteed to // be null, so it's safe to reinitialize it. return true; // The app continues executing. } // Renderer crashes because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!"); // In this example, the app itself crashes after detecting that the // renderer crashed. If you handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false; } }
Renderer Importance API
Gdy WebViewobiektydziałają wtrybie wieloprocesowym, masz pewną swobodę w zakresie tego, jak aplikacja obsługuje sytuacje, w których brakuje pamięci. Możesz użyć interfejsu Renderer Importance API, który został wprowadzony w Androidzie 8.0, aby ustawić zasady priorytetu dla mechanizmu renderowania przypisanego do konkretnego obiektu WebView. Możesz na przykład chcieć, aby główna część aplikacji była nadal wykonywana, gdy proces renderowania wyświetlający obiekty WebView aplikacji zostanie zakończony. Możesz to zrobić na przykład wtedy, gdy spodziewasz się, że obiekt WebView nie będzie wyświetlany przez dłuższy czas, aby system mógł odzyskać pamięć używaną przez moduł renderujący.
Ten fragment kodu pokazuje, jak przypisać priorytet procesowi renderowania powiązanemu z obiektami WebView aplikacji:
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
W tym konkretnym fragmencie priorytet renderera jest taki sam jak domyślny priorytet aplikacji lub jest z nim powiązany. Argument true obniża priorytet renderera do RENDERER_PRIORITY_WAIVED, gdy powiązany obiekt WebView nie jest już widoczny. Innymi słowy, argument true oznacza, że aplikacja nie dba o to, czy system utrzymuje proces renderowania. Ten niższy poziom priorytetu sprawia, że w sytuacjach, gdy brakuje pamięci, proces renderowania jest przerywany.
Więcej informacji o tym, jak system radzi sobie w sytuacjach, gdy jest mało pamięci, znajdziesz w artykule Procesy i cykl życia aplikacji.