5 Compilar
SITO edited this page 2026-08-20 00:14:35 +02:00

Compilar la APK

⚠ Rama experimental, no oficial. El Oasis oficial es https://github.com/epsylon/oasis · Volver a la portada

La APK se construye con un proyecto Gradle propio, en android/. Ya no se parte del APK oficial como molde.

Qué hay dentro de la APK

Qué se reutiliza y qué es nuevo

Tres bibliotecas nativas se toman tal cual del APK existente:

Fichero Qué es
libnode.so nodejs-mobile v18.20.4 oficial (OpenSSL 3.0.13+quic). Artefacto público: no hay que compilar Node
libnative-lib.so 6,8 KB. Un solo símbolo JNI que arranca Node
libc++_shared.so Runtime de C++

Por eso el namespace del módulo es com.solarnethub.oasis: JNI resuelve por nombre y la clase puente tiene que vivir en ese paquete. El identificador de la aplicación sí es propio, net.laenre.oasis, y por eso se instala junto a la oficial.

No hace falta el NDK.

Pasos

# 1. bibliotecas nativas y empaquetado del backend
cd android
./scripts/prepare.sh ../../oasis_mobile      # o la ruta de un APK

# 2. compilar
./gradlew assembleDebug                       # o assembleRelease para firmar

De dónde sale node_modules

Esto no es obvio y es donde se atasca cualquiera que lo intente.

El node_modules del móvil no es el que produce un npm install normal: son unos 137 MB podados y sin un solo binario nativo, frente a 1,4 GB con 35 binarios de una instalación de escritorio. Por eso el arranque fuerza criptografía en JavaScript puro.

prepare.sh lo saca del APK base y sustituye solo el código. Es seguro porque las 98 dependencias son idénticas entre versiones.

Si algún día lo rellenas con un npm install normal, la APK se llevará binarios de Linux de escritorio que en Android no sirven, y pesará diez veces más.

Publicar una versión

scripts/release.sh hace el ciclo entero y siempre igual, se lance a mano o desde un runner:

export JAVA_HOME=/opt/android-studio/jbr        # un JDK con javac
export ANDROID_HOME=$HOME/Android/Sdk
export OASIS_APK_BASE=../oasis-v0.8.7.apk       # solo la primera vez

cd android
./scripts/release.sh                             # compila y verifica, sin publicar
./scripts/release.sh --release                   # firmada
./scripts/release.sh --release --publish         # y la sube a las releases

Verifica cuatro cosas antes de dar nada por bueno, y son las que han cazado fallos reales en esta rama:

Comprueba Por qué
Que la APK lleva nodejs-project.zip Una APK sin backend compila, instala y arranca igual
Que lleva libnode.so Sin él no hay Node que ejecutar
Que declara CAMERA y RECORD_AUDIO Si se pierden, adiós videollamadas, y no se nota hasta pulsar Llamar
Que la firma es válida Y enseña la huella para publicarla

Las versiones no se editan a mano: el versionCode sale del número de commits (sube solo, y Android exige que suba) y el versionName de package.json, que es de donde lo saca también el backend —así la versión que muestra la aplicación no puede discrepar de la de la APK—.

La release se crea como borrador. Publicar una APK firmada sin que nadie la mire no debería poder pasar por descuido.

Desde gitea

.gitea/workflows/apk.yml hace lo mismo desde un runner. No se dispara con cada commit —la APK son más de 100 MB— sino a mano o al crear un tag v*.

El runner necesita JDK 17 con compilador, el SDK de Android, node, zip y unzip. Uno pelado no vale. Los secretos que hay que dar de alta están en la cabecera del fichero.

Firmar

La contraseña nunca en el repositorio ni en gradle.properties:

export OASIS_KEYSTORE=/ruta/oasis-alfa-key.jks
export OASIS_KEYSTORE_PASS=...
export OASIS_KEY_ALIAS=oasis
./gradlew assembleRelease

Y comprobar siempre antes de publicar:

apksigner verify --print-certs app-release.apk
unzip -l app-release.apk | grep nodejs-project.zip   # debe pesar más de 20 MB
aapt dump permissions app-release.apk | grep -E "CAMERA|RECORD_AUDIO"

La segunda línea importa: si el backend no se empaquetó bien, la APK compila, instala y arranca sin Oasis dentro.

Huella de la APK publicada

Antes de instalar una APK descargada de un servidor propio, comprueba la huella:

apksigner verify --print-certs oasis.apk

Compilación de prueba actual (firmada con clave de desarrollo, no de distribución):

SHA-256: f1857dcae344b067cfc4d10345c72627fb34c57824e7da776082daee74d6542d

Cuando haya una versión firmada para distribuir, su huella se publicará aquí y en la release. Una huella distinta significa que esa APK no la hemos construido nosotros.

Requisitos

JDK 17 o superior con compilador. Ojo: el OpenJDK de algunas distribuciones es solo runtime y no trae javac; el proyecto apunta al JDK que trae Android Studio.

Si Gradle se queja con JAVA_HOME is set to an invalid directory, apúntalo a un JDK que exista de verdad:

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

Qué pesa y cuánto ocupa

APK compilada ~112 MB
De eso, libnode.so 49 MB, sin comprimir
De eso, el backend empaquetado 34 MB
Espacio necesario para instalar ~350 MB (el backend se descomprime al primer arranque)

Las bibliotecas nativas van sin comprimir dentro de la APK. Pesa más de descarga, pero Android las mapea directamente desde el paquete en vez de extraer otra copia al disco, así que el móvil acaba usando menos espacio.

Probar en el emulador

adb install -r app/build/outputs/apk/debug/app-debug.apk
adb logcat -s OASIS-NODE:V

El log tiene que llegar a [Oasis] Backend started on port 3000. Si la instalación falla por espacio, adb shell pm clear net.laenre.oasis libera los datos descomprimidos —pero borra la identidad SSB de esa instalación.

Mejoras del envoltorio propio

  • targetSdk 35.
  • Tráfico sin cifrar permitido solo hacia el propio dispositivo, en vez de permitido en general.
  • Copia de seguridad de Android desactivada: adb backup ya no puede sacar tu identidad de SSB.
  • El backend corre como servicio en primer plano, así que sobrevive en segundo plano. Antes se declaraba el permiso pero no había servicio, y el backend moría al salir de la app.

Un servicio en primer plano tiene que enseñar una notificación, y desde Android 13 eso requiere permiso del usuario. El envoltorio lo pide al primer arranque.

Si se deniega, el backend sigue funcionando: lo que se pierde es el aviso de que está corriendo, y con él la garantía de que el sistema no lo mate al quedarse sin memoria.