android: wrapper propio, con los permisos que faltaban para las videollamadas
Hasta ahora la APK salia re-firmando la de epsylon, y su classes.dex no implementa WebChromeClient.onPermissionRequest. Sin ese metodo el WebView deniega por defecto todo getUserMedia, asi que las videollamadas de Karvan no podian funcionar por mucho que se parchease el manifest: la lista de permisos es estatica y se fija al compilar. El wrapper cierra las dos puertas. Declara CAMERA, RECORD_AUDIO y MODIFY_AUDIO_SETTINGS, pero no se conceden al instalar: son permisos peligrosos y se piden en tiempo de ejecucion la primera vez que se pulsa Llamar. Si nadie llama, no se pide nada. uses-feature required=false evita excluir dispositivos sin camara. Reutiliza las tres librerias nativas tal cual: libnode.so es nodejs-mobile v18.20.4 oficial y libnative-lib.so son 6,8 KB con un unico simbolo JNI. De ahi que el namespace sea com.solarnethub.oasis —JNI resuelve por nombre— mientras el applicationId es net.laenre.oasis, que permite instalarla junto a la oficial. No hace falta NDK ni compilar Node. De paso corrige cosas del APK actual: targetSdk 35, trafico en claro permitido solo hacia loopback en vez de usesCleartextTraffic global, allowBackup a false para que adb backup no saque el .ssb, y el backend en un servicio en primer plano en el proceso :node, que ademas es lo que permitira reiniciarlo limpio para el cambio de identidad. El APK actual declara FOREGROUND_SERVICE pero no registra ningun servicio, de modo que el backend muere al pasar a segundo plano. Los binarios no se versionan: scripts/prepare.sh extrae las librerias y empaqueta el backend. La keystore se pasa por entorno. Verificado: ./gradlew assembleDebug construye una APK de 52 MB con las tres librerias, targetSdk 35 y los permisos declarados; su DEX contiene onPermissionRequest, PermissionRequest, CAMERA y RECORD_AUDIO, donde el APK actual tiene cero de los cuatro. Falta probarla en un dispositivo real.
This commit is contained in:
parent
ace175cca3
commit
32f6d2269c
22 changed files with 944 additions and 0 deletions
90
android/README.md
Normal file
90
android/README.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Wrapper Android propio
|
||||
|
||||
Proyecto Gradle para construir la APK de la rama sin depender del APK oficial como
|
||||
molde.
|
||||
|
||||
## Por que existe
|
||||
|
||||
El APK que se venia usando es el de epsylon re-firmado, y su `classes.dex` **no
|
||||
implementa `WebChromeClient.onPermissionRequest`**. Sin ese metodo el WebView de
|
||||
Android deniega por defecto toda peticion de `getUserMedia()`, de modo que las
|
||||
videollamadas de Karvan no pueden funcionar por mucho que se parchee el manifest:
|
||||
la lista de permisos es estatica y hay que declararla al compilar.
|
||||
|
||||
Este wrapper resuelve las dos puertas: declara los permisos y los concede al
|
||||
contenido web solo tras el consentimiento del usuario.
|
||||
|
||||
## Permisos: declarados, no concedidos
|
||||
|
||||
`CAMERA`, `RECORD_AUDIO` y `MODIFY_AUDIO_SETTINGS` figuran en el manifest porque
|
||||
Android exige que la lista sea fija. Pero son permisos peligrosos: **se piden en
|
||||
tiempo de ejecucion la primera vez que se pulsa Llamar**, no al instalar. Si nadie
|
||||
llama, no se pide nada y la app no accede a la camara ni al microfono.
|
||||
|
||||
`uses-feature ... required="false"` evita excluir de la tienda a dispositivos sin
|
||||
camara o sin microfono.
|
||||
|
||||
## Que reutiliza y que es nuevo
|
||||
|
||||
Las tres librerias nativas se toman tal cual del APK existente:
|
||||
|
||||
- `libnode.so` — nodejs-mobile **v18.20.4** oficial (OpenSSL 3.0.13+quic), un
|
||||
artefacto publico; no hay que compilar Node.
|
||||
- `libnative-lib.so` — 6,8 KB, un solo simbolo JNI:
|
||||
`Java_com_solarnethub_oasis_OasisActivity_startNodeWithArguments`.
|
||||
- `libc++_shared.so`
|
||||
|
||||
Por eso el `namespace` del modulo es `com.solarnethub.oasis`: JNI resuelve por
|
||||
nombre y la clase puente tiene que vivir en ese paquete. El `applicationId` si es
|
||||
propio (`net.laenre.oasis`), asi que la app se instala junto a la oficial sin
|
||||
pisarla.
|
||||
|
||||
Si algun dia se quiere soltar el `.so` de epsylon, reimplementar esos 6,8 KB son
|
||||
unas 40 lineas de C++ contra las cabeceras de nodejs-mobile, y ahi si haria falta
|
||||
el NDK.
|
||||
|
||||
## Mejoras sobre el APK actual
|
||||
|
||||
- `targetSdk 35` (el actual se quedo en uno ya caducado para la tienda).
|
||||
- Trafico en claro permitido **solo hacia loopback** via
|
||||
`network_security_config`, en vez de `usesCleartextTraffic="true"` global.
|
||||
- `allowBackup="false"`: `adb backup` deja de poder extraer `~/.ssb`.
|
||||
- El backend corre en un servicio en primer plano, en el proceso `:node`, asi que
|
||||
sobrevive en segundo plano — imprescindible para recibir llamadas. El APK actual
|
||||
declara `FOREGROUND_SERVICE` pero no registra ningun servicio.
|
||||
- Al descomprimir el backend se descartan las entradas con rutas sospechosas
|
||||
(zip slip).
|
||||
|
||||
## Construir
|
||||
|
||||
```sh
|
||||
# 1. dependencias del backend (una vez)
|
||||
(cd ../src/server && npm install)
|
||||
|
||||
# 2. librerias nativas + empaquetado del backend
|
||||
./scripts/prepare.sh ../../oasis_mobile # o la ruta de un APK
|
||||
|
||||
# 3. compilar
|
||||
./gradlew assembleDebug # o assembleRelease
|
||||
```
|
||||
|
||||
Para firmar la release, por entorno (la keystore nunca al repositorio):
|
||||
|
||||
```sh
|
||||
export OASIS_KEYSTORE=/ruta/oasis-alfa-key.jks
|
||||
export OASIS_KEYSTORE_PASS=...
|
||||
export OASIS_KEY_ALIAS=oasis
|
||||
./gradlew assembleRelease
|
||||
```
|
||||
|
||||
## Requisitos
|
||||
|
||||
JDK 17 o superior **con compilador**. El OpenJDK del sistema puede ser solo
|
||||
runtime; `gradle.properties` apunta al JDK que trae Android Studio. Cambia esa
|
||||
linea si compilas en otra maquina.
|
||||
|
||||
## Estado
|
||||
|
||||
Compila y genera APK con los permisos y el `onPermissionRequest` en su sitio.
|
||||
**Falta probarlo en un dispositivo real**: que arranque el backend, que la
|
||||
interfaz cargue y que `getUserMedia` resuelva al pulsar Llamar.
|
||||
Loading…
Add table
Add a link
Reference in a new issue