Publicaste una compilación nueva, pasaste a la VPN y la misma pantalla dejó de cargar. En Android 9 y posteriores la explicación más habitual es más aburrida: la plataforma rechaza HTTP simple para las apps que apuntan a la API 28 o superior, y la VPN solo cambió suficiente contexto para dejarlo al descubierto. El error que ves depende del cliente HTTP, por eso casi nunca dice cleartext.

Qué es en realidad ese fallo

Desde Android 9 la plataforma bloquea cleartext de forma predeterminada en cuanto una app apunta al nivel de API 28 o superior. La plataforma rechaza la petición a una dirección HTTP simple antes de que salga un solo paquete del dispositivo. El error que veas depende de la biblioteca HTTP: a veces un fallo de red genérico, a veces un tiempo de espera agotado, a veces un mensaje que nombra cleartext sin rodeos. Lo que nunca hace es llegar a tu servidor. Android documenta el valor predeterminado y la alternativa limitada por dominio en su guía de configuración de seguridad.

Un navegador en el mismo dispositivo todavía puede cargar la página, y esa es la pista que casi todo el mundo pasa por alto. Los navegadores no están sujetos a la política de seguridad de red de tu app.

Por qué se culpa a la VPN

Normalmente cambian tres cosas a la vez. Puede que la app resuelva otro nombre de host tras conectarse la VPN, que el dispositivo sea nuevo con una compilación más reciente, o que la propia compilación haya pasado a un nivel de API objetivo que activa el valor predeterminado. La VPN se ve y el SDK objetivo no, así que la VPN se lleva el ticket.

Compara los niveles objetivo de las compilaciones vieja y nueva antes de tocar la configuración de red. Una app que apunta a 27 o menos está exenta, y eso explica todos los informes de «a mí me funciona en el móvil viejo».

Dónde acaba realmente el indicador de Expo

En un proyecto de Expo gestionado, añadir un ajuste a app.json no edita un manifiesto de Android, porque el manifiesto lo producen el prebuild y las compilaciones de desarrollo. El plugin de configuración es lo que escribe el ajuste en esa fase. La ruta admitida es expo-build-properties, configurado en la configuración de la app con la opción cleartext bajo android.

{
  "plugins": [
    ["expo-build-properties", {
      "android": { "usesCleartextTraffic": true }
    }]
  ]
}

El fragmento solo define la opción del plugin; el manifiesto se produce después. Ejecuta un prebuild o una compilación nueva del cliente de desarrollo y, antes de volver a probar, revisa el AndroidManifest.xml generado en busca de android:usesCleartextTraffic, porque una recarga solo de JS conserva el manifiesto antiguo. Ajusta la versión del plugin al SDK de Expo con el que corre el proyecto. Las opciones del plugin cambian entre versiones, y un fragmento copiado de otro SDK es una fuente fiable de no-ops silenciosos.

El flujo bare y la opción más estrecha

Para React Native bare el equivalente es android:usesCleartextTraffic en el elemento application, o una configuración de seguridad de red que permita cleartext solo para dominios concretos. La forma limitada por dominio es la preferible, porque permite la API interna y deja todo lo demás en HTTPS. También documenta su propia lista de excepciones, y esa es la parte que preguntará un revisor.

Ninguno de los dos enfoques cambia el valor predeterminado de la plataforma para nada que no hayas nombrado.

Primero demuéstralo con el registro del dispositivo

Antes de editar la configuración, obtén el fallo exacto. adb logcat en un dispositivo conectado muestra el rechazo de cleartext de la plataforma y nombra el componente que lo provocó. Un socket rechazado, un nombre que no se resuelve o un handshake TLS fallido apuntan a otro sitio por completo, y habilitar cleartext solo debilitaría la app para nada.

Después mantén la producción honesta. Cleartext es aceptable para un punto de laboratorio que no puede ofrecer TLS, y solo durante el tiempo más corto que puedas planificar. Si la API puede terminar TLS dentro de la red privada, pon el certificado en el almacén de confianza del dispositivo y deja cleartext desactivado, porque el túnel cifra el camino hasta su salida y nada más allá.

Cuando el punto responda por HTTPS, quita el permiso, vuelve a compilar y prueba en la VPN y en Wi-Fi normal en la misma sesión. La resolución de nombres puede diferir entre esos dos caminos, y solo el par te dice cuál dice la verdad.

Artículos relacionados