diff --git a/GUIA_DE_DESARROLLO.md b/GUIA_DE_DESARROLLO.md index 7afc884..c1af603 100644 --- a/GUIA_DE_DESARROLLO.md +++ b/GUIA_DE_DESARROLLO.md @@ -221,6 +221,8 @@ perdido los cambios (el CSS, por ejemplo). Por eso `sobre_oficial.sh` pone en el descomprime de nuevo. La config de cada cual (`src/configs`) se guarda aparte y se conserva. +Cómo está hecha la APK del dev por dentro (sacado con REA): `docs/ARQUITECTURA_APK.md`. + ## Lo que todavía está mal diff --git a/docs/ARQUITECTURA_APK.md b/docs/ARQUITECTURA_APK.md new file mode 100644 index 0000000..59128ff --- /dev/null +++ b/docs/ARQUITECTURA_APK.md @@ -0,0 +1,119 @@ +# Cómo está hecha la APK de Oasis + +Análisis de la APK oficial de epsylon (`oasis-v1.3.3.apk`, sha256 `4e8d60d4…5550d`) +con REA 6.7.0 y JADX headless 0.7.1, el 20/10/2026. Lo que se cita sale del código +decompilado de `com.solarnethub.oasis.OasisActivity`; las salidas completas están +en `OASIS_APK/ANALISIS_REA/` (fuera del repo). + + +## Las piezas + +La app es una envoltura Android pequeña (cuatro clases propias) alrededor de un +servidor Node.js que corre dentro del móvil, con nodejs-mobile. + +``` +APK +├── classes.dex OasisActivity pantalla: WebView, extracción, arranque de node +│ OasisService servicio en primer plano (sigue vivo con la app cerrada) +│ OasisAudioBridge, OasisStreamDecoder micro, altavoz y cámara del Teléfono +├── lib/*/libnode.so node para el móvil +└── assets/nodejs-project.zip + └── nodejs-project/ main.js, package.json, src/ (backend, vistas, CSS, node_modules) +``` + +La interfaz no es nativa: es HTML que sirve node en `http://127.0.0.1:3000` y que la +WebView enseña. Todo lo que vemos (vistas, CSS, textos) va dentro del zip. + + +## El arranque + +`onCreate`: + +1. `isExtractionNeeded()`: mira si hay que descomprimir. +2. `configureWebView()` y la pantalla de carga. +3. En otro hilo: `copyNodeProjectIfNeeded()` y después `startNode()`, que lanza + `node nodejs-project/main.js` y el servicio en primer plano. +4. Cuando node responde en `127.0.0.1:3000`, la WebView carga la página. + + +## Cuándo se descomprime el zip + +```java +// copyNodeProjectIfNeeded() +File file2 = new File(file, ".version"); +String appVersion = getAppVersion(); // versionName + "." + versionCode +String strTrim = file2.exists() ? readFile(file2).trim() : null; +if (file.exists() && appVersion.equals(strTrim)) { + Log.i("OASIS", "Node project already up to date (v" + appVersion + ")"); + return; +} +... +stashLegacyState(file3, file4); // copia src/configs a .configs-stash +deleteRecursive(file); +extractZipAsset(ASSET_ZIP, ...); +restoreLegacyState(file4, file3); // vuelve a poner los configs de antes +writeFile(file2, appVersion); +``` + +Solo se descomprime si cambia `versionName.versionCode`. Una APK nueva con el mismo +nombre y número de versión arranca con el código de la vez anterior, aunque dentro +lleve otro. Eso es lo que pasaba con nuestras APK de prueba: el `versionCode` solo +subía con cada commit, y al instalar una APK hecha sobre el mismo commit (o con +cambios sin commitear) se veía el CSS y las vistas de antes. Desde el 20/10/2026 +`sobre_oficial.sh` pone una huella del código en el `versionName`. + +Al descomprimir se conservan los ficheros de `src/configs` (la config de cada cual: +tema, idioma, workflow, colores). Consecuencia: si cambiamos la config de serie en +`configs/oasis-config.json`, solo la ve quien instala de cero; quien actualiza se +queda con la suya. + + +## La WebView no guarda caché + +```java +// configureWebView() +settings.setCacheMode(2); // LOAD_NO_CACHE +this.webView.clearCache(true); +``` + +Cada página y cada hoja de estilo se piden de nuevo al node del móvil. Si después de +instalar se ve CSS viejo, no es la caché: es que node está sirviendo el código viejo +(ver el punto anterior). + +La WebView solo navega dentro de `127.0.0.1:3000` y `localhost:3000`. Los enlaces +a una `.apk` los descarga ella misma y el resto de enlaces http(s) los abre en otra +app (el navegador). Hay rutas que intercepta para el Teléfono (`/phone/speaker`, +`/phone/accept-speaker`). + + +## Lo que hace nuestra APK encima + +`android/scripts/sobre_oficial.sh` coge esta APK tal cual y cambia: + +- `assets/nodejs-project.zip`: nuestro `src/`, `main.js` y `package.json`, con el + `node_modules` del dev (el podado para el móvil). +- El paquete, a `net.laenre.oasis`, para que conviva con la oficial. +- El icono, por el adaptativo de `android/icono/`. +- `versionName`, a `-hacklab.`. + +La parte Android (Java, puente de audio, servicio) es la del dev sin tocar. + + +## Repetir el análisis + +```sh +npm install --global --prefix ~/.local rea-agents@6.7.0 +# JADX headless 0.7.1, comprobando la huella que fija REA +curl -fL -o jadx-headless-mcp-0.7.1-all.jar \ + https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp-0.7.1-all.jar +echo '6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75 jadx-headless-mcp-0.7.1-all.jar' | sha256sum -c - +export REA_JADX_MCP_JAR=$PWD/jadx-headless-mcp-0.7.1-all.jar JAVA_HOME=/opt/android-studio/jbr + +rea inspect-android-package oasis-v1.3.3.apk +rea inspect-android-class oasis-v1.3.3.apk com.solarnethub.oasis.OasisActivity +rea inspect-android-method oasis-v1.3.3.apk com.solarnethub.oasis.OasisActivity copyNodeProjectIfNeeded +``` + +Con cada versión nueva del dev conviene mirar otra vez `copyNodeProjectIfNeeded`, +`configureWebView` y el manifiesto: si cambia la forma de extraer o la caché, +`sobre_oficial.sh` puede tener que cambiar también.