Android предоставляет несколько API, которые помогут вам управлять объектами WebView , отображающими веб-контент в вашем приложении.
На этой странице описано, как использовать эти API для более эффективной работы с объектами WebView , повышая стабильность и безопасность вашего приложения.
API версий
Начиная с Android 7.0 (уровень API 24), пользователи могут выбирать из нескольких различных пакетов для отображения веб-контента в объекте WebView . Библиотека Jetpack Webkit включает метод getCurrentWebViewPackage() для получения информации о пакете, отображающем веб-контент в вашем приложении. Этот метод полезен при анализе ошибок, возникающих только тогда, когда ваше приложение пытается отобразить веб-контент, используя реализацию WebView из определенного пакета.
Для использования этого метода добавьте логику, показанную в следующем фрагменте кода:
Котлин
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);
Сервис безопасного просмотра Google
Для обеспечения более безопасного просмотра WebView ваши пользователи используют функцию Google Safe Browsing для проверки URL-адресов, что позволяет вашему приложению показывать пользователям предупреждение при попытке перехода на потенциально небезопасный веб-сайт.
Хотя значение по умолчанию для параметра EnableSafeBrowsing равно true, бывают случаи, когда может потребоваться включить безопасный просмотр только при определенных условиях или отключить его. Android 8.0 (уровень API 26) и более поздние версии поддерживают использование setSafeBrowsingEnabled() для переключения безопасного просмотра для отдельного объекта WebView .
Если вы хотите, чтобы все объекты WebView не проверялись на соответствие требованиям безопасного просмотра, добавьте следующий элемент <meta-data> в файл манифеста вашего приложения:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
Определите программные действия
Когда экземпляр WebView пытается загрузить страницу, классифицированную Google как известная угроза, WebView по умолчанию отображает всплывающее окно, предупреждающее пользователей об этой угрозе. На этом экране пользователям предоставляется возможность загрузить URL-адрес в любом случае или вернуться на предыдущую безопасную страницу.
Если вы ориентируетесь на Android 8.1 (уровень API 27) или более позднюю версию, вы можете программно определить, как ваше приложение реагирует на известную угрозу, следующими способами:
- Вы можете настроить, будет ли ваше приложение сообщать об известных угрозах в систему Safe Browsing.
- Вы можете настроить свое приложение так, чтобы оно автоматически выполняло определенное действие — например, возвращалось в безопасное место — каждый раз, когда встречает URL-адрес, классифицируемый как известная угроза.
Приведенные ниже фрагменты кода показывают, как настроить экземпляры WebView вашего приложения таким образом, чтобы они всегда возвращались в безопасное состояние после обнаружения известной угрозы:
MyWebActivity.java
Котлин
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
Котлин
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(); } } }
API геолокации HTML5
Для приложений, ориентированных на Android 6.0 (уровень API 23) и более поздние версии, API геолокации поддерживается только при использовании защищенных источников, таких как HTTPS. Любой запрос к API геолокации при использовании незащищенных источников автоматически отклоняется без вызова соответствующего метода onGeolocationPermissionsShowPrompt() .
Отказаться от сбора метрик
WebView позволяет загружать анонимные диагностические данные в Google, если пользователь даст на это согласие. Сбор данных осуществляется для каждого приложения, в котором используется WebView . Вы можете отказаться от этой функции, создав следующий тег в элементе <application> манифеста:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
Данные загружаются из приложения только в том случае, если пользователь дает на это согласие и приложение не отказывается от этого. Для получения дополнительной информации об отказе от предоставления диагностических данных см. раздел « Конфиденциальность пользователя в отчетах WebView» .
API обработки завершения
API обработки завершения (Termination Handling) обрабатывает случаи, когда процесс рендеринга объекта WebView завершается либо из-за того, что система завершает работу рендерера для освобождения необходимой памяти, либо из-за сбоя процесса рендеринга. Использование этого API позволяет вашему приложению продолжать выполнение, даже если процесс рендеринга завершился.
Если при загрузке определенной веб-страницы происходит сбой в работе средства отрисовки, попытка повторной загрузки той же страницы может привести к тому, что новый объект WebView будет демонстрировать то же самое поведение, связанное со сбоем отрисовки.
Следующий фрагмент кода демонстрирует, как использовать этот API в Activity :
Котлин
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; } }
API важности рендерера
Когда объекты WebView работают в многопроцессном режиме , у вас есть некоторая гибкость в том, как ваше приложение обрабатывает ситуации нехватки памяти. Вы можете использовать API Renderer Importance, представленный в Android 8.0, чтобы установить политику приоритета для рендерера, назначенного конкретному объекту WebView . В частности, вы можете захотеть, чтобы основная часть вашего приложения продолжала выполняться, когда рендерер, отображающий объекты WebView вашего приложения, завершает работу. Это может быть необходимо, например, если вы ожидаете, что объект WebView не будет отображаться в течение длительного времени, чтобы система могла освободить память, используемую рендерером.
Приведенный ниже фрагмент кода показывает, как назначить приоритет процессу рендеринга, связанному с объектами WebView вашего приложения:
Котлин
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
В этом конкретном фрагменте кода приоритет рендерера совпадает с приоритетом приложения по умолчанию или привязан к нему. Аргумент true снижает приоритет рендерера до RENDERER_PRIORITY_WAIVED , когда связанный объект WebView перестает быть видимым. Другими словами, аргумент true указывает на то, что вашему приложению все равно, будет ли система поддерживать процесс рендеринга активным. Фактически, этот более низкий уровень приоритета делает вероятным завершение процесса рендеринга в ситуациях нехватки памяти.
Чтобы узнать больше о том, как система обрабатывает ситуации с нехваткой памяти, см. раздел «Процессы и жизненный цикл приложения» .