Usa WebView
para entregar una aplicación web o una página web como parte de una aplicación cliente. La clase WebView
es una extensión de la clase View
de Android que te permite mostrar páginas web como parte del diseño de tu actividad. No incluye las funciones de un navegador web completamente desarrollado, como los controles de navegación o una barra de direcciones. De forma predeterminada, todo lo que WebView
hace es mostrar una página web.
WebView
puede ayudarte a proporcionar información en tu app que quizás debas actualizar, como un acuerdo para el usuario final o una guía del usuario. En tu app para Android, puedes crear un Activity
que contenga un WebView
y, luego, usarlo para mostrar el documento alojado en línea.
WebView
también puede ser útil cuando tu app proporciona datos al usuario que requieren una conexión a Internet para recuperar información, como el correo electrónico. En este caso, es posible que sea más fácil compilar una WebView
en tu app para Android que muestre una página web con todos los datos del usuario, en lugar de realizar una solicitud de red y, luego, analizar los datos y renderizarlos en un diseño de Android. En cambio, puedes diseñar una página web adaptada a dispositivos con tecnología Android y, luego, implementar un WebView
en tu app para Android que cargue la página web.
En este documento, se describe cómo comenzar a usar WebView
, cómo vincular JavaScript desde tu página web al código del cliente en tu app para Android, cómo controlar la navegación de páginas y cómo administrar ventanas cuando se usa WebView
.
Cómo trabajar con WebView en versiones anteriores de Android
Para usar de forma segura las funciones de WebView
más recientes en el dispositivo en el que se ejecuta tu app, agrega la biblioteca de AndroidX Webkit. Esta es una biblioteca estática que puedes agregar a tu aplicación para usar las APIs de android.webkit
que no están disponibles para versiones anteriores de la plataforma.
Agrégala a tu archivo build.gradle
de la siguiente manera:
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Groovy
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
Explora el ejemplo de WebView
en GitHub para obtener más detalles.
Cómo agregar una WebView a tu app
Para agregar un WebView
a tu app, puedes incluir el elemento <WebView>
en el diseño de tu actividad o establecer toda la ventana Activity
como una WebView
en onCreate()
.
Cómo agregar una WebView en el diseño de la actividad
Para agregar un WebView
a tu app en el diseño, agrega el siguiente código al archivo en formato XML de diseño de tu actividad:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
Para cargar una página web en el WebView
, usa loadUrl()
, como se muestra en el siguiente ejemplo:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
Agrega una WebView en onCreate()
Para agregar un WebView
a tu app en el método onCreate()
de una actividad, usa una lógica similar a la siguiente:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
Luego, carga la página:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
O carga la URL desde una string HTML:
Kotlin
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING) myWebView.loadData(encodedHtml, "text/html", "base64")
Java
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. String unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); myWebView.loadData(encodedHtml, "text/html", "base64");
Tu app debe tener acceso a Internet. Para obtener acceso a Internet, solicita el permiso INTERNET
en tu archivo de manifiesto, como se muestra en el siguiente ejemplo:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Puedes personalizar tu WebView
mediante una de las siguientes acciones:
- Habilita la compatibilidad con la pantalla completa mediante
WebChromeClient
. También se llama a esta clase cuando unWebView
necesita permiso para modificar la IU de la app host, por ejemplo, cuando se crean o cierran ventanas o se envían diálogos de JavaScript al usuario. Si deseas obtener más información sobre la depuración en este contexto, consulta Cómo depurar apps web. - Controlar eventos que afectan la renderización del contenido, como errores en el envío de formularios o en la navegación con
WebViewClient
También puedes usar esta subclase para interceptar la carga de URL. - Habilita JavaScript modificando
WebSettings
. - Usar JavaScript para acceder a los objetos del framework de Android que insertaste en una
WebView
Usa JavaScript en WebView
Si la página web que deseas cargar en tu WebView
usa JavaScript, debes habilitar JavaScript para tu WebView
. Después de habilitar JavaScript, puedes crear interfaces entre el código de tu app y el de JavaScript.
Cómo habilitar JavaScript
De forma predeterminada, JavaScript está inhabilitado en la WebView
. Puedes habilitarlo a través del WebSettings
adjunto a tu WebView
. Recupera WebSettings
con getSettings()
y, luego, habilita JavaScript con setJavaScriptEnabled()
.
Observa el siguiente ejemplo:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Java
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
WebSettings
proporciona acceso a otras opciones de configuración que podrían serte útiles. Por ejemplo, si desarrollas una aplicación web diseñada específicamente para el WebView
en tu app para Android, puedes definir una cadena de usuario-agente personalizada con setUserAgentString()
y, luego, consultar el usuario-agente personalizado en tu página web para verificar que el cliente que solicita la página web sea tu app para Android.
Cómo vincular el código JavaScript con el código de Android
Cuando desarrollas una aplicación web diseñada específicamente para el WebView
en tu app para Android, puedes crear interfaces entre tu código JavaScript y el código de Android del cliente. Por ejemplo, tu código JavaScript puede llamar a un método en tu código de Android para mostrar un Dialog
, en lugar de usar la función alert()
de JavaScript.
Para vincular una interfaz nueva entre tu código de JavaScript y Android, llama a addJavascriptInterface()
y pásale una instancia de clase para vincularla a tu código JavaScript y un nombre de interfaz que tu JavaScript pueda llamar para acceder a la clase.
Por ejemplo, puedes incluir la siguiente clase en tu app para Android:
Kotlin
/** Instantiate the interface and set the context. */ class WebAppInterface(private val mContext: Context) { /** Show a toast from the web page. */ @JavascriptInterface fun showToast(toast: String) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show() } }
Java
public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context. */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page. */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } }
En este ejemplo, la clase WebAppInterface
permite que la página web cree un mensaje Toast
mediante el método showToast()
.
Puedes vincular esta clase al código JavaScript que se ejecuta en tu WebView
con addJavascriptInterface()
, como se muestra en el siguiente ejemplo:
Kotlin
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
Java
WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android");
De esta manera, se crea una interfaz llamada Android
para JavaScript que se ejecuta en WebView
. En este punto, tu aplicación web tiene acceso a la clase WebAppInterface
. Por ejemplo, a continuación, te mostramos algo de HTML y JavaScript que crea un mensaje de aviso con la nueva interfaz cuando el usuario presiona un botón:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
No es necesario inicializar la interfaz Android
desde JavaScript. La WebView
la pone automáticamente a disposición de tu página web. Por lo tanto, cuando un usuario presiona el botón, la función showAndroidToast()
usa la interfaz Android
para llamar al método WebAppInterface.showToast()
.
Cómo controlar la navegación de páginas
Cuando el usuario presiona un vínculo de una página web en tu WebView
, de forma predeterminada, Android inicia una app que administra las URLs. Por lo general, se abre el navegador web predeterminado y se carga la URL de destino. Sin embargo, puedes anular este comportamiento para tu WebView
de modo que los vínculos se abran dentro de tu WebView
. Luego, puedes permitir que el usuario navegue hacia atrás y hacia adelante por el historial de páginas web que mantiene tu WebView
.
Para abrir los vínculos que presionó el usuario, proporciona un WebViewClient
para tu WebView
usando setWebViewClient()
.
Todos los vínculos que presione el usuario se cargarán en tu WebView
. Si deseas tener más control sobre dónde se carga un vínculo en el que se hizo clic, crea tu propio WebViewClient
que anule el método shouldOverrideUrlLoading()
. En el siguiente ejemplo, se supone que MyWebViewClient
es una clase interna de Activity
.
Kotlin
private class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { if (Uri.parse(url).host == "www.example.com") { // This is your website, so don't override. Let your WebView load // the page. return false } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { startActivity(this) } return true } }
Java
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if ("www.example.com".equals(request.getUrl().getHost())) { // This is your website, so don't override. Let your WebView load the // page. return false; } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); startActivity(intent); return true; } }
Luego, crea una instancia de este nuevo WebViewClient
para la WebView
:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
Ahora, cuando el usuario presiona un vínculo, el sistema llama al método shouldOverrideUrlLoading()
, que verifica si el host de la URL coincide con un dominio específico, como se definió en el ejemplo anterior. Si coincide, el método muestra un valor falso y no anula la carga de la URL. Permite que WebView
cargue la URL como de costumbre. Si el host de la URL no coincide, se creará un Intent
a fin de iniciar el Activity
predeterminado para controlar las URLs, lo que se resuelve en el navegador web predeterminado del usuario.
Cómo procesar las URLs personalizadas
WebView
aplica restricciones cuando se solicitan recursos y se resuelven vínculos
que usan un esquema de URL personalizada. Por ejemplo, si implementas devoluciones de llamada, como shouldOverrideUrlLoading()
o shouldInterceptRequest()
, WebView
las invoca solo para URLs válidas.
Por ejemplo, es posible que WebView
no llame a tu método shouldOverrideUrlLoading()
para vínculos como el siguiente:
<a href="showProfile">Show Profile</a>
Las URLs no válidas, como la que se muestra en el ejemplo anterior, se manejan de forma inconsistente en WebView
, por lo que te recomendamos que uses una URL con el formato correcto.
Puedes usar un esquema personalizado o una URL HTTPS para un dominio que controla tu organización.
En lugar de usar una cadena simple en un vínculo, como en el ejemplo anterior, puedes usar un esquema personalizado como el siguiente:
<a href="example-app:showProfile">Show Profile</a>
Luego, puedes controlar esta URL en tu método shouldOverrideUrlLoading()
de la siguiente
manera:
Kotlin
// The URL scheme must be non-hierarchical, meaning no trailing slashes. const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Java
// The URL scheme must be non-hierarchical, meaning no trailing slashes. private static final String APP_SCHEME = "example-app:"; @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(APP_SCHEME)) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8"); respondToData(urlData); return true; } return false; }
El objetivo principal de la API de shouldOverrideUrlLoading()
es iniciar intents para URLs específicas. Cuando la implementes, asegúrate de mostrar false
para las URLs que controla WebView
. Sin embargo, no estás limitado a iniciar intents. Puedes reemplazar los intents de inicio por cualquier comportamiento personalizado en las muestras de código anteriores.
Navegar por el historial de páginas web
Cuando tu WebView
anula la carga de URL, acumula automáticamente un historial de las páginas web visitadas. Puedes navegar hacia atrás y hacia adelante por el historial con goBack()
y goForward()
.
Por ejemplo, a continuación, se muestra cómo tu Activity
puede usar el botón Atrás del dispositivo para navegar hacia atrás:
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // Check whether the key event is the Back button and if there's history. if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) { myWebView.goBack() return true } // If it isn't the Back button or there isn't web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check whether the key event is the Back button and if there's history. if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it isn't the Back button or there's no web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event); }
Si tu app usa AndroidX AppCompat
1.6.0+, puedes simplificar aún más el fragmento anterior:
Kotlin
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Java
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
El método canGoBack()
muestra el valor "true" si hay un historial de páginas web que el usuario puede visitar. Del mismo modo, puedes usar canGoForward()
para verificar si hay un historial de versiones posteriores. Si no realizas esta verificación, después de que el usuario llega al final del historial, goBack()
y goForward()
no realizan ninguna acción.
Cómo controlar los cambios en la configuración del dispositivo
Durante el tiempo de ejecución, los cambios de estado de la actividad ocurren cuando cambia la configuración de un dispositivo, por ejemplo, cuando los usuarios rotan el dispositivo o descartan un editor de método de entrada (IME). Estos cambios provocan la destrucción de la actividad de un objeto WebView
y la creación de una nueva actividad, lo que también crea un nuevo objeto WebView
que carga la URL del objeto destruido. Para modificar el comportamiento predeterminado de tu actividad, puedes cambiar la forma en que controla los cambios de orientation
en tu manifiesto. Si quieres obtener más información para controlar los cambios de configuración durante el tiempo de ejecución, consulta Cómo administrar los cambios en la configuración.
Administrar ventanas
De forma predeterminada, las solicitudes para abrir ventanas nuevas se ignoran. Esto es así, independientemente de si las abre JavaScript o el atributo de destino en un vínculo. Puedes personalizar tu WebChromeClient
a fin de que proporcione tu propio comportamiento cuando se abran varias ventanas.
Para mantener tu app más segura, te recomendamos evitar que se abran ventanas emergentes y nuevas. La forma más segura de implementar este comportamiento es pasar "true"
a setSupportMultipleWindows()
, pero no anular el método onCreateWindow()
, del que depende setSupportMultipleWindows()
. Esta lógica evita que se cargue cualquier página que use target="_blank"
en sus vínculos.