Simplifica la implementación de WebView con Jetpack Webkit

En esta guía, se describen los beneficios de la biblioteca de Jetpack Webkit, se explica cómo funciona y cómo puedes implementarla en tus proyectos.

Descripción general

Las WebView son una parte esencial del desarrollo de Android, pero a veces pueden ser difíciles de administrar debido a las incoherencias en las funciones en las diferentes versiones del SO Android. Cada versión del SO Android proporciona un conjunto fijo de APIs de WebView. Debido a que Android se envía a un ritmo más lento que WebView, es posible que las APIs de Android no cubran todas las funciones de WebView disponibles. Esto genera una implementación de funciones más lenta y un aumento en los costos de prueba.

Jetpack Webkit resuelve estos problemas actuando como una capa de compatibilidad y aprovechando el APK de WebView actualizado en el dispositivo del usuario. También contiene APIs nuevas y modernas que están disponibles exclusivamente en esta biblioteca.

¿Por qué usar Jetpack Webkit?

Además de ofrecer compatibilidad entre versiones, Jetpack Webkit también ofrece APIs nuevas y modernas que pueden simplificar el desarrollo y mejorar la funcionalidad de tu app:

  • Habilita la autenticación moderna: WebView puede controlar sin problemas los estándares de autenticación web modernos, como WebAuthn, lo que permite el acceso basado en llaves de acceso. La biblioteca androidx.webkit te brinda control total sobre esta integración con el método WebSettingsCompat.setWebAuthenticationSupport(), que puedes usar para configurar el nivel de compatibilidad que requiere tu app.

  • Mejora el rendimiento: Ajusta el rendimiento de WebView con APIs como setBackForwardCacheEnabled o reduce la latencia de navegación con APIs de carga especulativa, como prefetchUrlAsync y prerenderUrlAsync. Para obtener más información, consulta Carga especulativa en WebView.

  • Aumenta la estabilidad: Recupera los procesos de renderizador bloqueados o que no responden sin fallar. Para obtener más información, consulta WebViewRenderProcess#terminate().

  • Ofrece un control detallado sobre los datos de navegación: Para borrar los datos de navegación almacenados por WebView para orígenes específicos, usa la clase WebStorageCompat.

  • Mejora la eficiencia del estado y la memoria: Serializa de forma segura el estado de navegación dentro del presupuesto de transacción de 1 MB y evita TransactionTooLargeException fallas con la serialización de estado limitada por tamaño con WebViewCompat.saveState(). Para obtener más información, consulta Cómo administrar de manera eficaz el estado de WebView.

Comprende los componentes

Para usar Jetpack Webkit de manera eficaz, debes comprender la relación entre los siguientes componentes:

  • WebView del sistema Android: Es el motor de renderización basado en Chromium que Google actualiza con regularidad a través de Google Play Store con el mismo ritmo que Chrome. Contiene las funciones más actualizadas y proporciona el código de implementación subyacente para todas las APIs de WebView.

  • APIs de framework (android.webkit): Son las APIs que se fijan a una versión específica del SO Android. Por ejemplo, una app en Android 10 solo puede acceder a las APIs que estaban disponibles cuando se lanzó esa versión. Por lo tanto, no puede usar las funciones nuevas que se agregaron al APK de WebView en actualizaciones más recientes. Por ejemplo, para controlar un renderizador que no responde con WebView#getWebViewRenderProcess(), solo puedes llamarlo en Android 10 y versiones posteriores.

  • Biblioteca de Jetpack Webkit (androidx.webkit): Es una biblioteca pequeña incluida en tu aplicación. Esta biblioteca actúa como un puente que llama al APK de WebView, en lugar de llamar a las APIs definidas en la plataforma de Android, que tiene una versión fija del SO. De esta manera, incluso cuando una aplicación se instala en un dispositivo que ejecuta una versión anterior del SO, como Android 10, la aplicación puede usar las funciones más recientes de WebView. Por ejemplo, WebViewCompat.getWebViewRenderProcess() funciona de manera similar a la API de framework, excepto que también se puede llamar en todas las versiones del SO anteriores a Android 10.

Si una API está disponible en el framework y en Jetpack Webkit, te recomendamos que elijas la versión de Jetpack Webkit. Esto ayuda a garantizar un comportamiento y una compatibilidad coherentes en la mayor cantidad de dispositivos.

Interacción entre Jetpack Webkit y APK

Las APIs de Jetpack Webkit se implementan en dos partes:

  • Jetpack Webkit estático: La biblioteca de Jetpack Webkit estática contiene una minoría del código responsable de implementar la API.

  • APK de WebView: El APK de WebView contiene la mayor parte del código.

Tu app llama a la API de Jetpack Webkit, que luego llama al APK de WebView.

Si bien controlas la versión de Jetpack Webkit en tu app, no puedes controlar las actualizaciones del APK de WebView en los dispositivos de los usuarios. Por lo general, la mayoría de los usuarios tienen versiones actualizadas del APK de WebView, pero tu app debe tener cuidado de no llamar a las APIs que no admite esa versión en particular del APK de WebView.

Jetpack Webkit también abstrae la necesidad de verificar las versiones de WebView de forma manual. Para determinar si una función está disponible, verifica su constante de función. Por ejemplo, WebViewFeature.WEB_AUTHENTICATION.

Cómo funcionan en conjunto

Jetpack Webkit une la brecha entre la API de framework estática y el APK de WebView que se actualiza con frecuencia. Cuando usas la API de Jetpack Webkit con el patrón de detección de funciones, la biblioteca realiza una verificación para ver si la función es compatible con el APK de WebView instalado en el dispositivo del usuario. Esto proporciona el beneficio de no tener que verificar la versión del SO Android (framework).

Si el APK de WebView es una versión lo suficientemente reciente, la biblioteca invoca la función. De lo contrario, informa que la función no está disponible, lo que evita que tu app falle y te permite controlar la situación sin problemas.

Compara las APIs de Jetpack Webkit y de framework

En esta sección, se comparan los métodos de implementación con y sin la biblioteca de Jetpack Webkit:

Habilita la autenticación moderna (WebAuthn)

Sin Jetpack Webkit

No es posible a través de las APIs de framework.

Con Jetpack Webkit

Aprovecha WebViewFeature.WEB_AUTHENTICATION para las verificaciones de compatibilidad.

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

Borra datos de un origen (almacenamiento específico del sitio)

Sin Jetpack Webkit

No hay una API directa para borrar datos de origen específicos. A menudo, se requiere borrar todos los datos.

Con Jetpack Webkit

Usa APIs de compatibilidad para borrar datos precisos. Puedes usar cualquiera de las siguientes opciones:

WebStorageCompat.getInstance().deleteBrowsingData()

O

WebStorageCompat.getInstance().deleteBrowsingDataForSite()

Obtén la versión de WebView

Sin Jetpack Webkit

Usa la clase de framework estándar.

val webViewPackage = WebView.getCurrentWebViewPackage()

Con Jetpack Webkit

Usa la capa de compatibilidad para una recuperación más segura.

val webViewPackage = WebViewCompat.getCurrentWebViewPackage()

Controla el renderizador que no responde (cliente de renderizador)

Sin Jetpack Webkit

Usa el método de framework estándar.

webView.setWebViewRenderProcessClient(myClient)

Con Jetpack Webkit

Usa WebViewCompat y una verificación de funciones para configurar el cliente.

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

Para obtener orientación sobre la implementación de estrategias de recuperación ante fallas, consulta Cómo controlar la finalización de WebView. Para obtener detalles de la API, consulta la androidx.webkit documentación de referencia.

Administra el estado guardado y el tamaño de la transacción

La API de WebViewCompat.saveState te permite aplicar límites de bytes y eliminar el historial de avance durante la serialización, lo que evita fallas de TransactionTooLargeException y preserva el historial de navegación esencial.

Sin Jetpack Webkit

Usa el método de framework estándar, que serializa toda la pila de navegación sin límites de tamaño y puede activar TransactionTooLargeException si la carga útil supera el límite de transacción de 1 MB de Android.

webView.saveState(outState)

Con Jetpack Webkit

Usa WebViewCompat para aplicar un límite máximo de bytes o descartar entradas de navegación hacia adelante, lo que protege contra los desbordamientos de transacciones.

WebViewCompat.saveState(webView, outState, maxSizeBytes)

Para obtener más información, consulta Cómo administrar de manera eficaz el estado de WebView.

Integra Jetpack Webkit en tu código

El uso de Jetpack Webkit aumenta las capacidades de la clase WebView estándar, pero no reemplaza por completo la clase WebView original.

Puedes seguir usando la android.webkit.WebView clase. Puedes agregarla a tus diseños XML y obtener una referencia a la instancia en tu código. Para acceder a las funciones de framework estándar, puedes llamar a los métodos directamente en la instancia de WebView o en su objeto de configuración.

Para acceder a las funciones modernas, usa los métodos auxiliares estáticos que proporciona Jetpack Webkit, como WebViewCompat y WebSettingsCompat. Pasa tu instancia de WebView existente a estos métodos.

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

Implementa Jetpack Webkit

Para implementar Jetpack Webkit, usa el siguiente procedimiento.

Paso 1: Agrega la dependencia

En el archivo build.gradle.kts o build.gradle de tu módulo, incluye la siguiente dependencia para agregar Jetpack Webkit:

Groovy

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

Kotlin

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

Jetpack Webkit contiene wrappers delgados, por lo que el impacto en el tamaño de tu aplicación es mínimo.

Paso 2: Adopta el patrón de detección de funciones

Para evitar fallas cuando se invocan APIs no disponibles, usa verificaciones de funciones. Te recomendamos que rodees cada invocación de API con una verificación de funciones y que consideres la lógica de resguardo para cuando la API no esté disponible.

Recomendamos el siguiente patrón para usar una API de WebView moderna:

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.
}

Este patrón ayuda a garantizar que la aplicación sea sólida. Debido a que la verificación de funciones se ejecuta primero, la aplicación no falla si la función no está disponible. La sobrecarga de rendimiento de la WebViewFeature#isFeatureSupported() verificación es insignificante.