c13d6baf60
Thin Jetpack Compose UI over the real Go client (pkg/client) compiled to a gomobile .aar, so the phone speaks NATS and runs the same end-to-end crypto as any other peer. Connect, create room (nats/matrix), publish and live-receive.
112 lines
4.4 KiB
Markdown
112 lines
4.4 KiB
Markdown
---
|
|
name: unibus_android
|
|
domain: tools
|
|
version: 0.1.0
|
|
description: "Cliente Android (Jetpack Compose) del bus unibus: conecta, crea salas y chatea con el mismo cliente Go (pkg/client) compilado a un .aar via gomobile, conservando el cifrado E2E."
|
|
tags: [messaging, nats, e2e, android, compose, kotlin, gomobile, client]
|
|
lang: kt
|
|
framework: compose
|
|
entry_point: "app/src/main/kotlin/com/fnregistry/unibus/MainActivity.kt"
|
|
dir_path: "projects/message_bus/apps/unibus_android"
|
|
repo_url: "https://gitea.organic-machine.com/dataforge/unibus_android"
|
|
uses_functions:
|
|
- fn_theme_kt_ui
|
|
- fn_tokens_kt_ui
|
|
- fn_stack_kt_ui
|
|
- fn_group_kt_ui
|
|
- fn_card_kt_ui
|
|
- fn_badge_kt_ui
|
|
- fn_button_kt_ui
|
|
- fn_text_kt_ui
|
|
- fn_title_kt_ui
|
|
- fn_text_input_kt_ui
|
|
- fn_switch_kt_ui
|
|
uses_types: []
|
|
e2e_checks:
|
|
- id: bind
|
|
cmd: "cd ../unibus && gomobile bind -target=android -androidapi 24 -o ../unibus_android/app/libs/unibus.aar github.com/enmanuel/unibus/mobile"
|
|
timeout_s: 600
|
|
- id: build
|
|
cmd: "fn run gradle_assemble_debug_bash_infra projects/message_bus/apps/unibus_android"
|
|
timeout_s: 360
|
|
---
|
|
|
|
# unibus_android
|
|
|
|
Cliente Android del bus de mensajería `unibus`. La aplicación es una fina capa de
|
|
interfaz en Jetpack Compose sobre el cliente Go real del bus: `pkg/client` se compila
|
|
a una librería nativa Android (`unibus.aar`) con `gomobile bind`, de modo que el teléfono
|
|
habla el protocolo NATS y ejecuta el mismo cifrado end-to-end (ChaCha20-Poly1305 +
|
|
Ed25519 + X25519) que cualquier otro peer. No se reimplementa ni el protocolo ni la
|
|
criptografía: hay una única fuente de verdad compartida con el resto del ecosistema.
|
|
|
|
## Arquitectura
|
|
|
|
```
|
|
MainActivity.kt (Compose UI)
|
|
└── mobile.Session (Kotlin, generado por gomobile)
|
|
└── unibus.aar (libgojni.so: pkg/client + nats.go + crypto del registry)
|
|
├── data plane → NATS TCP (nats://host:4250)
|
|
└── control plane → HTTP REST (http://host:8470)
|
|
```
|
|
|
|
El wrapper Go que define la API plana del binding vive en
|
|
`projects/message_bus/apps/unibus/mobile/unibus.go` (paquete `mobile`): expone
|
|
`NewSession`, `CreateRoom`, `Join`, `Publish`, `Subscribe`, `Request` y la interfaz
|
|
`FrameListener` con tipos compatibles con gomobile (string, []byte, int, error,
|
|
interface).
|
|
|
|
## Regenerar el binding (.aar)
|
|
|
|
Tras tocar `pkg/client` o el wrapper `mobile/`:
|
|
|
|
```bash
|
|
cd projects/message_bus/apps/unibus
|
|
export ANDROID_HOME=$HOME/android-sdk
|
|
export ANDROID_NDK_HOME=$(ls -d $HOME/android-sdk/ndk/* | head -1)
|
|
export PATH="$PATH:$(go env GOPATH)/bin"
|
|
gomobile bind -target=android -androidapi 24 \
|
|
-o ../unibus_android/app/libs/unibus.aar \
|
|
github.com/enmanuel/unibus/mobile
|
|
```
|
|
|
|
## Build del APK
|
|
|
|
```bash
|
|
fn run gradle_assemble_debug_bash_infra projects/message_bus/apps/unibus_android
|
|
# o, directo:
|
|
cd projects/message_bus/apps/unibus_android && ./gradlew :app:assembleDebug
|
|
# salida: app/build/outputs/apk/debug/app-debug.apk
|
|
```
|
|
|
|
## Probarlo contra el bus
|
|
|
|
1. Levantar el control plane real (NATS embebido + REST de membresía):
|
|
```bash
|
|
cd projects/message_bus/apps/unibus
|
|
go run ./cmd/membershipd # HTTP :8470, NATS :4250
|
|
```
|
|
2. En el **emulador** (`Pixel_API34`), instalar el APK. La app usa `host = 10.0.2.2`,
|
|
que el emulador mapea al loopback del PC, así que conecta sin más configuración.
|
|
3. En la app: Conectar → Crear sala → escribir un mensaje. El mensaje viaja al bus por
|
|
NATS y vuelve al propio suscriptor (eco del subject), confirmando el camino completo
|
|
APK → bus → APK.
|
|
|
|
## Gotchas
|
|
|
|
- `cmd/membershipd` escucha en `127.0.0.1` (líneas `addr := "127.0.0.1:" + httpPort`).
|
|
Desde el emulador funciona (10.0.2.2 → loopback del host). Para un **teléfono real** en
|
|
la LAN o vía Tailscale hay que bindear el control plane y el NATS embebido a `0.0.0.0`
|
|
y usar la IP de red del PC/VPS en los campos Host de la app.
|
|
- El control plane v1 es HTTP sin TLS; el manifest declara `usesCleartextTraffic="true"`.
|
|
Para producción, exponer el bus con TLS y quitar ese flag.
|
|
- El `.aar` pesa ~24 MB (runtime Go embebido) y el APK debug ~54 MB. Es esperado: el
|
|
cliente Go completo viaja dentro.
|
|
- `onFrame` del `FrameListener` llega en una goroutine de entrega de NATS; la UI hace
|
|
`Handler(mainLooper).post { ... }` antes de tocar el estado de Compose.
|
|
|
|
## Capability growth log
|
|
|
|
- v0.1.0 (2026-06-05) — baseline: conectar, crear sala (modo nats/matrix), publicar y
|
|
recibir mensajes en vivo. Binding gomobile del `pkg/client` con cifrado E2E intacto.
|