Android udostępnia kilka interfejsów API, które ułatwiają zarządzanie obiektami WebView
, które wyświetlają treści z internetu w aplikacji.
Na tej stronie opisujemy, jak używać tych interfejsów API do efektywniejszej pracy z obiektami WebView
, co pozwoli zwiększyć stabilność i bezpieczeństwo aplikacji.
Interfejs API wersji
Od Androida 7.0 (poziom interfejsu API 24) użytkownicy mają do wyboru kilka różnych pakietów do wyświetlania treści z internetu w obiekcie WebView
.
Biblioteka AndroidX.webkit zawiera metodę getCurrentWebViewPackage()
do pobierania informacji związanych z pakietem, który wyświetla zawartość internetową Twojej aplikacji. Ta metoda jest przydatna podczas analizy błędów występujących tylko wtedy, gdy aplikacja próbuje wyświetlić treści internetowe za pomocą implementacji WebView
w danym pakiecie.
Aby skorzystać z tej metody, dodaj funkcję logiczną przedstawioną 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 większe bezpieczeństwo podczas przeglądania internetu, WebView
umożliwia weryfikację adresów URL za pomocą Bezpiecznego przeglądania Google. Dzięki temu aplikacja wyświetla użytkownikom ostrzeżenie, gdy próbują wejść na potencjalnie niebezpieczną stronę.
Chociaż domyślna wartość EnableSafeBrowsing
to „prawda”, w niektórych przypadkach możesz chcieć włączyć Bezpieczne przeglądanie tylko warunkowo lub tylko je wyłączyć. Android 8.0 (poziom interfejsu API 26) i nowsze obsługują użycie setSafeBrowsingEnabled()
do przełączania Bezpiecznego przeglądania w przypadku pojedynczego obiektu WebView
.
Jeśli chcesz, żeby 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ń związanych z automatyzacją
Gdy wystąpienie elementu WebView
próbuje wczytać stronę sklasyfikowaną przez Google jako znane zagrożenie, WebView
domyślnie wyświetla reklamę pełnoekranową z ostrzeżeniem o znanym zagrożeniu. Umożliwia on użytkownikom wczytanie adresu URL mimo to lub powrót do bezpiecznej strony.
Jeśli kierujesz aplikację na Androida 8.1 (poziom interfejsu API 27) lub nowszego, możesz automatycznie określić, jak aplikacja ma reagować na znane zagrożenie w ten sposób:
- Możesz określić, czy Twoja aplikacja zgłasza znane zagrożenia do Bezpiecznego przeglądania.
- Możesz ustawić automatyczne wykonywanie przez aplikację określonego działania – na przykład powrót do zabezpieczeń – za każdym razem, gdy napotka adres URL sklasyfikowany jako znany zagrożenie.
Z poniższych fragmentów kodu dowiesz się, jak nakazać wystąpieniam w aplikacji funkcję WebView
zawsze wracaniu do stanu zabezpieczeń po napotkaniu znanego zagrożenia:
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!"); } } }); } }
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(); } } }
Interfejs API geolokalizacji HTML5
W przypadku aplikacji kierowanych na Androida 6.0 (poziom interfejsu API 23) i nowsze wersje interfejs API geolokalizacji jest obsługiwany tylko w przypadku bezpiecznych źródeł, takich jak HTTPS. Wszystkie żądania wysyłane do interfejsu Geolocation API z niezabezpieczonych źródeł są automatycznie odrzucane bez wywoływania odpowiedniej metody onGeolocationPermissionsShowPrompt()
.
Zrezygnuj z zbierania danych
WebView
może przesyłać do Google anonimowe dane diagnostyczne, jeśli użytkownik wyrazi na to zgodę. W przypadku każdej aplikacji, która tworzy instancję WebView
, zbierane są dane dotyczące poszczególnych aplikacji. Możesz zrezygnować z tej funkcji, tworząc w elemencie <application>
pliku manifestu następujący 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 zgodę, a aplikacja tego nie zrobi. Więcej informacji o rezygnowaniu z raportów danych diagnostycznych znajdziesz w artykule Prywatność użytkowników w raportach WebView.
Zakończenie obsługi interfejsu API
Interfejs End handling API obsługuje przypadki, w których proces renderowania obiektu WebView
wyłącza się, ponieważ system zamyka mechanizm renderowania, by odzyskać niezbędną pamięć, lub w wyniku awarii tego procesu. Dzięki niemu aplikacja będzie mogła działać nadal, nawet jeśli proces renderowania zostanie wyłączony.
Jeśli mechanizm renderowania ulegnie awarii podczas wczytywania konkretnej strony internetowej, próba ponownego załadowania tej samej strony może spowodować, że nowy obiekt WebView
będzie wykazywać ten sam błąd renderowania.
Ten 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; } }
Interfejs API mechanizmu renderowania
Gdy obiekty WebView
działają w trybie wielu procesów, masz niewielką elastyczność w tym, jak aplikacja postępuje w przypadku braku pamięci. Za pomocą wprowadzonego w Androidzie 8.0 interfejsu Renderer Importance API możesz ustawić zasadę priorytetu dla mechanizmu renderowania przypisanego do konkretnego obiektu WebView
. Być może główna część aplikacji ma być wykonywana po tym, jak mechanizm renderowania wyświetlający obiekty WebView
aplikacji zostanie wyłączony. Możesz to zrobić na przykład wtedy, gdy spodziewasz się, że obiekt WebView
nie będzie wyświetlany przez długi czas, aby system mógł odzyskać pamięć wykorzystywaną przez mechanizm renderowania.
Ten fragment kodu pokazuje, jak przypisać priorytet do procesu renderowania powiązanego z obiektami WebView
w Twojej aplikacji:
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
W tym fragmencie kodu priorytet mechanizmu renderowania jest taki sam jak domyślny lub powiązany z aplikacją. Argument true
obniża priorytet mechanizmu renderowania do RENDERER_PRIORITY_WAIVED
, gdy powiązany obiekt WebView
nie jest już widoczny. Inaczej mówiąc, argument true
wskazuje, że aplikacja nie dba o to, czy system utrzymuje aktywność mechanizmu renderowania. W przypadku braku pamięci proces renderowania może zakończyć się niepowodzeniem.
Więcej informacji o tym, jak system obsługuje sytuacje z małą ilością pamięci, znajdziesz w sekcji Procesy i cykl życia aplikacji.