Cómo administrar objetos WebView

Android proporciona varias APIs para ayudarte a administrar la WebView objetos que muestran contenido web en tu app.

En esta página, se describe cómo usar estas APIs para trabajar con WebView de forma más eficaz, lo que mejora la estabilidad y seguridad de tu app.

API de versión

A partir de Android 7.0 (nivel de API 24), los usuarios pueden elegir entre varias diferentes paquetes para mostrar contenido web en un objeto WebView. La función AndroidX.webkit biblioteca incluye el getCurrentWebViewPackage() método para recuperar información relacionada con el paquete que muestra la contenido de tu app. Este método es útil cuando se analizan errores que solo ocurren cuando tu app intenta mostrar contenido web usando la interfaz de un paquete implementación de WebView.

Para usar este método, agrega la lógica que se muestra en el siguiente fragmento de código:

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);

Servicio de Navegación segura de Google

Para brindar a tus usuarios una experiencia de navegación más segura, WebView los objetos verifican las URLs con Navegación segura de Google, lo que permite que tu app muestre una advertencia a los usuarios cuando intenten navegar a una un sitio web potencialmente peligroso.

Aunque el valor predeterminado de EnableSafeBrowsing es verdadero, son casos en los que quizás desees habilitar solo la Navegación segura de manera condicional o inhabilitarla. Android 8.0 (nivel de API 26) y versiones posteriores admiten el uso de setSafeBrowsingEnabled() si quieres activar o desactivar la Navegación segura para un objeto WebView individual.

Si deseas inhabilitar la Navegación segura en todos los objetos WebView agrega el siguiente elemento <meta-data> al directorio archivo de manifiesto:

<manifest>
    <application>
        <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
                   android:value="false" />
        ...
    </application>
</manifest>

Cómo definir acciones programáticas

Cuando una instancia de WebView intenta cargar una página que está clasificada por Google como una amenaza conocida, WebView de forma predeterminada muestra un anuncio intersticial que advierte a los usuarios sobre la amenaza conocida. Esta pantalla te ofrece a los usuarios la opción de cargar la URL de todas formas o regresar a una página anterior que sea la seguridad de los recursos aprovisionados.

Si tienes como objetivo Android 8.1 (nivel de API 27) o una versión posterior, puedes definir de manera programática cómo responde tu app a una amenaza conocida en las siguientes situaciones: maneras:

  • Puedes controlar si tu app informa amenazas conocidas a Safe Navegación.
  • Puedes hacer que tu app realice automáticamente una acción determinada, como como regresar a un estado seguro, cada vez que encuentre una URL clasificada como amenaza conocida.

Los siguientes fragmentos de código muestran cómo dar instrucciones a las instancias de tu app de WebView para volver siempre a un estado seguro después de encontrar un mensaje de error amenaza:

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();
        }
    }
}

API de HTML5 Geolocation

Para las apps orientadas a Android 6.0 (nivel de API 23) y versiones posteriores, la API de Geolocation solo es compatible con orígenes seguros, como HTTPS. Cualquier solicitud a la La API de Geolocation en orígenes no seguros se rechaza automáticamente sin invocar el método onGeolocationPermissionsShowPrompt() correspondiente

Cómo inhabilitar la recopilación de métricas

WebView tiene la capacidad de subir datos de diagnóstico anónimos para a Google cuando el usuario otorga su consentimiento. Los datos se recopilan por app para cada app que cree una instancia de WebView. Puedes inhabilitar esta opción esta función creando la siguiente etiqueta en el archivo Elemento <application>:

<manifest>
    <application>
    ...
    <meta-data android:name="android.webkit.WebView.MetricsOptOut"
               android:value="true" />
    </application>
</manifest>

Los datos solo se suben desde una aplicación si el usuario da su consentimiento y la app no la inhabilita. Más información para inhabilitar los datos de diagnóstico generación de informes, consulta Privacidad del usuario en WebView informes.

API de Termination Handling

La API de Rescisión Handling controla casos en los que el proceso del renderizador para una WebView desaparece, ya sea porque el sistema finaliza el renderizador para recuperarlo la memoria necesaria o porque falla el proceso del renderizador. Con esta API, puedes permiten que tu app continúe ejecutándose aunque desaparezca el proceso del renderizador.

Si un procesador falla mientras carga una página web determinada, intenta volver a cargar esa misma página puede provocar que un nuevo objeto WebView presentan el mismo comportamiento de falla de renderización.

El siguiente fragmento de código ilustra cómo usar esta API dentro de 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;
    }
}

API de Renderer Importance

Cuando los objetos WebView operar en multiproceso, tienes cierta flexibilidad en cuanto a la forma en que tu app controla situaciones de falta de memoria. Puedes usar la API de Renderer Importance, que se presentó en Android 8.0, para establecer una política de prioridad para el procesador asignado a un determinado WebView. En particular, quizás quieras que la parte principal de tu app se siga ejecutando cuando un procesador que muestre Se cierran WebView objetos. Podrías hacer esto, por ejemplo, si esperas no mostrar el objeto WebView por mucho tiempo para que la puede recuperar memoria que usaba el procesador.

En el siguiente fragmento de código, se muestra cómo asignar una prioridad al procesador proceso asociado con los objetos WebView de tu app:

Kotlin

val myWebView: WebView = ...
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)

Java

WebView myWebView;
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);

En este fragmento en particular, la prioridad del representador es la misma que, o a la que está vinculada la prioridad predeterminada para la aplicación. El true disminuye la prioridad del renderizador a RENDERER_PRIORITY_WAIVED Cuando el objeto WebView asociado deja de estar visible. En otro palabras, un argumento true indica que a tu app no le importa si el sistema mantiene activo el proceso del renderizador. De hecho, este nivel de prioridad más bajo hace que sea probable que el proceso del renderizador se cierre por falta de memoria. situaciones.

Para obtener más información sobre la manera en que el sistema maneja situaciones de poca memoria, consulta Procesos y app ciclo de vida.