Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.3 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0072g | gamedev — Android build (NDK + touch input + virtual gamepad + WalletConnect) | pendiente | feature |
|
multi-app | media |
|
2026-05-10 | 2026-05-17 |
|
Objetivo
Compilar el runtime gamedev a APK Android, ejecutarlo en device fisico, gestionar touch input + virtual gamepad overlay, integrar wallet crypto via WalletConnect deep links, y mantener APK base ≤ 20 MB.
Toolchain
Requisitos en host:
- Android SDK (cmdline-tools)
- Android NDK r27+ (LTS)
- JDK 17
- Gradle 8+
adbpara deploy a device
Funcion bash: bash/functions/infra/setup_android_ndk.sh que descarga e instala SDK+NDK en ~/android-sdk/. Idempotente.
Estructura del proyecto Android
SDL3 ya provee plantilla Android. Adaptar:
cpp/apps/<app>/android/
build.gradle # Top-level
settings.gradle
app/
build.gradle # App module (NDK config, ABI filters)
AndroidManifest.xml
src/main/
java/com/.../MainActivity.java # Hereda SDL3 main activity
jni/ # NDK wrapper
Android.mk / CMakeLists.txt
res/
drawable/icon.png
values/strings.xml
CMake cross-compile
# Ya en cpp/apps/<app>/CMakeLists.txt, sin cambios.
# Build invocado desde Android Studio o gradle:
# ./gradlew assembleRelease
ABIs target:
arm64-v8a— obligatorio (todos los devices modernos)armeabi-v7a— opcional (devices viejos)x86_64— solo para emulador
Cada ABI ≈ 5-7 MB del APK base. Distribuir como App Bundle (AAB) en Play Store, que entrega solo la ABI del device.
Touch input
cpp/functions/gamedev/input_unified (de 0072b) ya tiene array touches[8]. Aqui lo poblamos.
SDL3 provee:
SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION
input_unified mapea a InputState.touches. Cada touch tiene id, x, y (normalizado 0..1), pressure.
Virtual gamepad
Funcion nueva: virtual_gamepad_cpp_gamedev (impure):
struct VGamepadCfg {
bool show_dpad; // Lado izquierdo
bool show_buttons; // Lado derecho (A, B, X, Y)
float dpad_radius; // En pixels
float button_radius;
Color color_active;
Color color_idle;
};
void vgamepad_render(const VGamepadCfg& cfg, InputState& out_input,
const InputState& touch_input);
Logica:
- Detecta touches dentro del area del dpad → setea
out_input.left/right/up/down. - Detecta touches en area de botones → setea
out_input.action_a/b/x/y. - Render: dibuja con
sprite_batchlos iconos del dpad y botones.
Estilo: semi-transparente, configurable color/tamaño. Sprites por defecto en cpp/assets/vgamepad/ (dpad.png, btn_a.png, ...).
Auto-hide opcional cuando hay gamepad fisico conectado (Bluetooth):
if (SDL_GetGamepads(NULL) > 0) cfg.show_dpad = cfg.show_buttons = false;
Safe area / notch
Funcion: safe_area_cpp_gamedev (pure):
struct SafeArea { int top, bottom, left, right; }; // En pixels
SafeArea safe_area_get(SDL_Window* w);
SDL3: SDL_GetWindowSafeArea(SDL_Window*, SDL_Rect*). Render UI dentro de ese rect.
Permisos
AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- WalletConnect deep link: -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="<app_name>" />
</intent-filter>
NO pedir permisos de:
- Storage (escribir solo en
getFilesDir(), no necesita permiso). - Camera/Mic — solo si el juego los usa.
Crypto wallet (WalletConnect)
En mobile no hay window.ethereum. Usuario abre el juego, pulsa "Connect Wallet" → SDK genera URI WalletConnect → abre app de wallet (MetaMask Mobile, Trust, Rainbow) via deep link → wallet firma → callback con resultado.
Plan: empotrar WalletConnect Sign SDK version C (¿existe?). Si no:
- Implementar protocolo WalletConnect v2 minimo en C++ (WebSocket + JSON-RPC + AES-256-GCM). ~1000 LoC.
- Funcion:
walletconnect_session_cpp_crypto,walletconnect_request_cpp_crypto.
Alternativa pragmatica: webview embebida con bridge JS (mismo patron que 0072e). Android tiene WebView, iOS tiene WKWebView. Pesa mas pero reusa codigo.
Decision pendiente — sub-issue dedicado al protocolo si se complica.
Pipeline de build
bash/functions/pipelines/build_android_cpp_pipelines.sh:
#!/usr/bin/env bash
set -euo pipefail
APP="$1"
cd "cpp/apps/$APP/android"
./gradlew assembleRelease
APK="app/build/outputs/apk/release/app-release.apk"
echo "APK: $(stat -c%s "$APK") bytes"
Para deploy a device:
adb install -r app/build/outputs/apk/release/app-release.apk
adb shell am start -n com.fn.<app>/.MainActivity
Firma del APK
Generar keystore una vez:
keytool -genkey -v -keystore release.keystore -keyalg RSA -keysize 2048 \
-validity 10000 -alias <app_name>
Guardar en ~/keystores/ (gitignored) y referenciarlo en gradle.properties:
RELEASE_STORE_FILE=/home/lucas/keystores/<app>.keystore
RELEASE_STORE_PASSWORD=...
RELEASE_KEY_ALIAS=...
RELEASE_KEY_PASSWORD=...
Tamaño
| Componente | Tamaño aprox |
|---|---|
arm64-v8a .so (runtime) |
4-6 MB |
| SDL3 lib | 1-2 MB |
| Java glue | 50 KB |
| Resources (icons) | 50 KB |
| Assets bundle | depende del juego |
APK base objetivo: ≤ 20 MB (sin assets pesados).
Logging
adb logcat | grep <app> para ver printf y crashes. SDL3 redirige stdout/stderr a logcat por default.
Funcion: bash/functions/infra/android_logcat_filter.sh <app_name> que tail -f con filtros utiles.
e2e_checks
e2e_checks:
- id: build_apk
cmd: "bash bash/functions/pipelines/build_android_cpp_pipelines.sh <app>"
timeout_s: 600
- id: apk_size
cmd: "test $(stat -c%s cpp/apps/<app>/android/app/build/outputs/apk/release/app-release.apk) -lt 20971520"
- id: apk_install_emulator
cmd: "bash bash/functions/infra/android_emulator_smoke.sh <app>"
severity: warning # Emulador puede no estar disponible
timeout_s: 300
Tests en device
Smoke test manual al principio. Automatizar despues con adb shell input tap + adb shell screencap + comparacion de imagenes (si vale la pena).
Criterio de exito
engine_democorre en Android device (Pixel/Samsung de prueba).- Touch input + virtual gamepad funcionan.
- Audio sin glitches.
- Safe area respetada (notch invisible no tapa UI).
- APK release ≤ 20 MB.
- WalletConnect: firma de mensaje funciona con MetaMask Mobile (basico, profundizar en sub-issue dedicado si hace falta).
- Pipeline reproducible desde Linux WSL + Windows.
Riesgos
- WalletConnect en C++ puro — protocolo no trivial. Plan B: webview.
- NDK API levels — minSdk 24 (Android 7). Devices < 7 fuera.
- App Bundle requerido en Play Store —
bundleReleaseen lugar deassembleReleasepara production. - Apple-style audio latency — Android variable. miniaudio AAudio backend ayuda en API 26+.
No-objetivos
- Push notifications.
- Google Play Billing — out of scope, prioridad crypto payments.
- AdMob / ads.
- iOS (en 0072h).