From e0ff70c1384c2cc14b74801766411e3150f132ab Mon Sep 17 00:00:00 2001 From: s1to Date: Wed, 19 Aug 2026 19:34:06 +0200 Subject: [PATCH] android: rotar la pantalla rompia la app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Al girar el movil aparecia ERR_CONNECTION_REFUSED y ahi se quedaba. La lista de configChanges estaba incompleta —faltaba smallestScreenSize, que es justo lo que cambia al rotar—, asi que Android destruia y recreaba la Activity: el WebView se perdia y volvia a cargar la URL, a veces antes de que el backend escuchara. Con la lista completa, rotar ya no recrea nada y ademas no se pierde lo que estuvieras escribiendo. Y se anade una red de seguridad que no habia: onReceivedError vuelve a esperar al backend y recarga la ultima pagina que si cargo, en vez de dejar el error de Chromium en pantalla. Cubre tres casos mas, todos comprobados en el emulador: - Matar el proceso :node con la app abierta (lo que hace Android cuando necesita memoria): antes se quedaba muerta, ahora vuelve sola en unos 19 segundos. - Cambiar de identidad, que reinicia el backend a proposito. - Arranques lentos en moviles con poca memoria. Un guard evita que se acumulen hilos esperando al mismo puerto, porque onReceivedError se dispara una vez por recurso que falle. Probado ademas: boton atras, modo avion, trim-memory RUNNING_CRITICAL y am kill con reapertura. Todo eso ya iba bien. --- android/app/src/main/AndroidManifest.xml | 6 +++- .../java/net/laenre/oasis/MainActivity.kt | 31 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 70b6dd2..edcd992 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -38,10 +38,14 @@ android:exported="false" android:foregroundServiceType="dataSync" /> + diff --git a/android/app/src/main/java/net/laenre/oasis/MainActivity.kt b/android/app/src/main/java/net/laenre/oasis/MainActivity.kt index 17a87fe..65e4ee5 100644 --- a/android/app/src/main/java/net/laenre/oasis/MainActivity.kt +++ b/android/app/src/main/java/net/laenre/oasis/MainActivity.kt @@ -76,6 +76,27 @@ class MainActivity : AppCompatActivity() { startActivity(Intent(Intent.ACTION_VIEW, u)) return true } + + /** + * Red de seguridad: si una pagina del backend no carga, se vuelve a esperar + * y se reintenta, en vez de dejar el ERR_CONNECTION_REFUSED de Chromium en + * pantalla. Pasa cuando el backend todavia no escucha (arranque lento), y + * tambien cuando se ha reiniciado —al cambiar de identidad, o porque Android + * mato el proceso del servicio estando en segundo plano—. + */ + override fun onPageFinished(v: WebView?, url: String?) { + // se recuerda para poder volver aqui si luego hay que reintentar + if (url != null && url.startsWith("http://127.0.0.1:3000")) lastGoodUrl = url + } + + override fun onReceivedError(v: WebView?, req: WebResourceRequest?, err: WebResourceError?) { + if (req?.isForMainFrame != true) return // un css o una imagen no cuentan + val u = req.url ?: return + if (!isLocal(u)) return // paginas de fuera, ni tocarlas + Log.w("OasisNode", "la pagina no ha cargado (${'$'}u); reintentando") + loaded = false + waitAndLoad() + } } // Sin este WebChromeClient.onPermissionRequest, el WebView DENIEGA por defecto @@ -155,6 +176,8 @@ class MainActivity : AppCompatActivity() { */ private var loadAttempt = 0 private var loaded = false + @Volatile private var waiting = false // hay un hilo esperando al backend + private var lastGoodUrl: String? = null // ultima pagina que cargo bien /** * Espera a que el backend acepte conexiones y entonces carga la interfaz. @@ -182,6 +205,10 @@ class MainActivity : AppCompatActivity() { } private fun waitAndLoad() { + // onReceivedError puede dispararse varias veces seguidas (la pagina y sus + // recursos); sin esto se acumularian hilos esperando al mismo puerto + if (waiting) return + waiting = true showStatus(0) Log.i("OasisNode", "esperando al backend en 127.0.0.1:3000") Thread { @@ -196,14 +223,16 @@ class MainActivity : AppCompatActivity() { if (ok) { Handler(Looper.getMainLooper()).post { loaded = true + waiting = false Log.i("OasisNode", "backend listo tras " + (i / 2) + "s, cargando interfaz") - web.loadUrl(targetUrl()) + web.loadUrl(lastGoodUrl ?: targetUrl()) } return@Thread } if (i % 8 == 0) Handler(Looper.getMainLooper()).post { if (!loaded) showStatus(i) } Thread.sleep(500); i++ } + waiting = false }.start() }