Cuando se utiliza un WebView en Android para mostrar contenido HTML local, puede surgir un problema si el código JavaScript de la página intenta cargar recursos adicionales utilizando XMLHttpRequest. Específicamente, al intentar acceder a archivos locales (por ejemplo, plantillas para funcionalidades de enrutamiento en AngularJS), las versiones de Android 4.1 y posteriores introdujeron restricciones de seguridad que impiden estas solicitudes.
Este bloqueo se manifiesta con un error similar al siguiente:
Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'file:///android_asset/content.txt'.
Antes de Android 4.1, las páginas locales dentro de un WebView podía realizar solicitudes XMLHttpRequest a archivos locales sin inconvenientes. Sin embargo, para garantizar la seguridad, Android 4.1 introdujo la limitación que causa este comportamiento inconsistente entre versiones del sistema operativo.
Solución
Para restaurar la funcionalidad de XMLHttpRequest para acceder a archivos locales en páginas dentro de un WebView en Android 4.1 y versiones posteriores, es necesario habiiltar explícitamente una configuración específica en WebSettings. La opción setAllowFileAccessFromFileURLs(true) permite que las páginas cargadas desde el sistema de archivos (incluido el directorio android_asset) puedan realizar solicitdues de acceso a archivos.
A continuación, se muestra un ejemplo de cómo implementar esta configuración en la actividad principal de Android:
MainActivity.java
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
public class MainActivity extends Activity {
@SuppressLint({"SetJavaScriptEnabled", "NewApi"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = findViewById(R.id.webView1);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
// Habilitar acceso a archivos locales desde URLs de archivos para versiones >= JELLY_BEAN
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
settings.setAllowFileAccessFromFileURLs(true);
}
// Cargar la página HTML local
webView.loadUrl("file:///android_asset/index.html");
}
}
index.html
Este archivo HTML demuestra cómo se puede usar XMLHttpRequest para cargar y mostrar el contenido de un archivo local llamado content.txt.
<html>
<head>
<meta charset="utf-8" />
<title>Carga de Archivo Local</title>
</head>
<body>
<h1 id="contentBox"></h1>
<script>
// Función para mostrar el contenido
function displayMessage(message) {
var contentBox = document.getElementById("contentBox");
contentBox.innerHTML = message;
}
// Crear una instancia de XMLHttpRequest
var req = new XMLHttpRequest();
// Manejar la carga exitosa de la respuesta
req.onload = function () {
displayMessage(req.responseText);
};
// Manejar errores en la solicitud
req.onerror = function (error) {
displayMessage("Error al cargar el archivo: " + error.message);
};
try {
// Abrir y enviar la solicitud GET para el archivo local
req.open("GET", "content.txt", true);
req.send();
}
catch (ex) {
displayMessage("Excepción: " + ex.message);
}
</script>
</body>
</html>
Asegúrate de tener un archivo llamado content.txt en el directorio assets de tu proyecto Android, junto con el archivo index.html, para que este ejemplo funcione correctamente.