Construí Traverba — un traductor en tiempo real que funciona 100% en tu teléfono, sin APIs en la nube. Reconocimiento de voz, traducción en 108 idiomas, OCR por cámara en 92 escrituras, superposición de traducción de pantalla, transcripción de archivos y chat grupal sin conexión por Bluetooth para hasta 7 personas.
Toda la app está construida con Flutter más código nativo de plataforma para las tareas más exigentes. Aquí explico qué hace la app, por qué Flutter fue la elección correcta y los mayores desafíos que enfrenté al publicarla en producción tanto en iOS como en Android.
Qué Hace la App
Traverba tiene cinco funciones principales, todas sin conexión:
Traducción de Voz en Vivo — Habla en un idioma y escucha y lee la traducción en otro. Tres modos: dentro de la app, captura flotante de audio del sistema (traduce audio de Zoom/Teams/Meet) y micrófono flotante. Lectura en voz alta automática en el idioma de destino.
Traducción por Cámara — Apunta tu cámara a un menú, letrero, formulario o documento. Dos motores OCR: modo Basic (ML Kit) para lecturas ágiles, y modo Professional (PaddleOCR) para escrituras complejas como CJK, árabe, cirílico y Devanagari. Admite 92 idiomas. La app reemplaza el texto extranjero con el texto traducido directamente sobre la imagen.
Traducción de Pantalla — Una superposición flotante que traduce el texto dentro de cualquier app. ¿Viendo anime, leyendo noticias en coreano, jugando un videojuego en japonés o recibiendo un mensaje de WeChat? Toca el botón de superposición y el texto se traduce en el lugar. Sin cambiar de app.
Transcripción de Archivos — Importa archivos de audio o video (mp3, m4a, wav, mp4) y obtén transcripciones con marcas de tiempo, mostrando el texto original y la traducción en paralelo.
Chat Grupal Sin Conexión — Hasta 7 personas se conectan mediante una red Bluetooth en malla. Cada persona habla su idioma. Cada mensaje se traduce al idioma de todos los participantes en tiempo real. Sin internet. Sin servidor. Cada teléfono gestiona su propio ASR y traducción de forma independiente.
Todo esto se ejecuta localmente en el procesador del teléfono. Sin claves de API, sin costos de servidor, sin que los datos salgan del dispositivo.
Por Qué Flutter
Al inicio evalué Flutter, React Native y código completamente nativo (codebases separados en Swift + Kotlin).
Una sola base de código multiplataforma era innegociable. Para un desarrollador en solitario, mantener dos codebases nativas para una app de esta complejidad no era realista. La capa de UI en Dart — ajustes, burbujas de chat, vistas de transcripción, tour de incorporación, hojas de descarga, selectores de idioma — representa aproximadamente el 60% del código total. Escribir eso dos veces habría duplicado el tiempo del proyecto.
El sistema de canales de plataforma de Flutter hizo que la integración nativa fuera práctica. El trabajo más exigente de IA (inferencia ASR, traducción con LLM, OCR, red Bluetooth en malla, superposiciones flotantes) se ejecuta en Swift/Kotlin nativo a través de canales de plataforma y de métodos. Flutter no intenta ser el motor de IA — es la capa de UI y orquestación que conecta los motores nativos.
El rendimiento fue suficientemente bueno. La preocupación con Flutter para este tipo de app es la sobrecarga — cada milisegundo importa cuando encadenas ASR → traducción → TTS en una conversación. En la práctica, la capa Flutter agrega una latencia insignificante porque el cálculo pesado ocurre en código nativo. La capa Dart gestiona el estado, el enrutamiento y las actualizaciones de UI, y lo hace bien.
La recarga en caliente aceleró drásticamente la iteración de UI. Con cinco superficies de funciones distintas (voz, cámara, pantalla, archivo, chat grupal), cada una con múltiples estados y modos, la capacidad de iterar en la UI sin reconstruir fue un multiplicador de productividad significativo.
La Arquitectura: Flutter como Orquestador
La app sigue una división clara:
La capa Flutter/Dart gestiona:
- Toda la UI (Material 3, layouts adaptables para teléfono y tablet)
- Gestión de estado y enrutamiento de funciones
- Selección de idioma/locale y preferencias del usuario
- Gestión de descargas de modelos opcionales
- Economía de monedas y control de suscripción
- Tour guiado de incorporación
La capa nativa gestiona (a través de canales de plataforma):
- Inferencia ASR (sherpa-onnx / whisper.cpp)
- Traducción con LLM (Gemma a través del motor en dispositivo)
- Traducción tradicional con modelos ONNX NMT
- OCR por cámara (ML Kit + PaddleOCR)
- Texto a voz
- Red Bluetooth en malla para chat grupal
- Superposición flotante (traducción de pantalla + captura de audio del sistema)
- Gestión del presupuesto de memoria y carga/expulsión de modelos
El puente entre estas capas es un conjunto de canales de plataforma con contratos bien definidos. El lado Dart envía comandos ("iniciar ASR para cantonés", "traducir este texto del japonés al inglés", "capturar pantalla y aplicar OCR"). El lado nativo devuelve resultados de forma asíncrona.
Tres Modelos ASR, Enrutamiento Automático
Ningún modelo de reconocimiento de voz cubre bien todos los idiomas. En lugar de aceptar baja calidad para algunos idiomas, la app incluye tres modelos especializados:
- Parakeet Optimizado para inglés. Incluido con la app para ASR en inglés instantáneo sin necesidad de descarga.
- Whisper.cpp Amplia cobertura multilingüe en más de 30 idiomas.
- Qwen3-ASR Optimizado para CJK con soporte dedicado para el cantonés.
Cuando el usuario selecciona un idioma de origen, la capa de enrutamiento en Dart elige el mejor modelo e indica al lado nativo qué motor activar. El usuario nunca ve ni gestiona la selección del modelo.
La parte complicada es la memoria. Estos modelos van de 500 MB a 1,9 GB en RAM. Cargar los tres simultáneamente haría colapsar la mayoría de los teléfonos. Un planificador de presupuesto de memoria (escrito en Dart, consultando estadísticas nativas de memoria) rastrea qué está cargado y expulsa el modelo usado menos recientemente cuando se necesita cargar uno nuevo. Un almacén de preferencias de backend recuerda qué backend de cómputo (NPU, GPU, CPU) funcionó en cada dispositivo específico, de modo que las ejecuciones posteriores omiten los backends fallidos.
108 Idiomas con Dos Niveles de Traducción
La traducción ocurre a través de dos rutas:
Nivel 1 — Modelos NMT tradicionales (61 idiomas): Rápidos, con poca memoria, buena calidad para pares de idiomas con muchos recursos. Modelos ONNX ejecutados mediante sherpa-onnx en ambas plataformas.
Nivel 2 — LLM Gemma en dispositivo (47 idiomas adicionales): Para idiomas sin modelos NMT dedicados (yoruba, amhárico, lao, birmano y otros), un modelo Gemma 2B cuantizado maneja la traducción de forma local. Más lento que el Nivel 1, pero amplía la cobertura a idiomas que los modelos tradicionales sirven mal.
La capa Dart gestiona qué nivel usar según el par de idiomas. El usuario experimenta una interfaz unificada.
OCR por Cámara: Motor Dual, 92 Idiomas
La traducción por cámara ejecuta dos motores que el usuario puede seleccionar:
El modo Basic usa el reconocimiento de texto en dispositivo de Google ML Kit. Ágil, maneja bien el latín, el cirílico y el CJK. Ideal para uso en visor en tiempo real.
El modo Professional usa PaddleOCR ejecutado en el dispositivo. Mayor precisión para diseños complejos, escrituras mixtas, texto curvo y bajo contraste. Usa una puerta de monedas (5 monedas por captura) ya que es más intensivo en cómputo.
Una lección aprendida de la manera difícil: iOS solo incluye el modelo de script OCR latino de forma predeterminada. CJK, Devanagari y árabe requieren agregar explícitamente pods específicos del script al Podfile. El fallo es completamente silencioso — ML Kit devuelve resultados vacíos para scripts no admitidos sin ningún error. Si estás construyendo OCR multilingüe en iOS con ML Kit, revisa tu Podfile.
Superposición Flotante: Nativa, No Flutter
Las funciones de traducción de pantalla y audio del sistema se ejecutan como superposiciones nativas fuera de la superficie de renderizado de Flutter. En Android, es un servicio de superposición del sistema escrito en Kotlin. En iOS, usa APIs de captura de pantalla en Swift.
Estas superposiciones se comunican de vuelta al motor de traducción de Flutter a través de canales de plataforma. El desafío arquitectónico es la gestión del ciclo de vida — la superposición debe mantenerse activa mientras la actividad principal de Flutter puede estar en segundo plano.
Una lección crítica: en iOS, las instancias de puente nativo deben ser retenidas fuertemente (estáticas o mantenidas por un singleton). Si el puente es una variable de instancia que nada retiene, ARC la recolectará y todos los closures de manejadores se convertirán silenciosamente en operaciones sin efecto. Perdí días con un indicador de progreso de descarga atascado en 0% porque el puente estaba siendo recolectado. Sin crash, sin error, solo fallo silencioso.
Chat Grupal por Bluetooth
El chat grupal sin conexión usa un protocolo de red en malla Bluetooth. Cada teléfono actúa como receptor y relé. Los mensajes se transmiten a todos los dispositivos conectados. Cada dispositivo ejecuta su propio ASR y traducción de forma independiente — no hay teléfono "anfitrión" ni "servidor".
Flutter gestiona la UI del chat, el estado de los mensajes y la gestión de participantes. La pila Bluetooth es completamente nativa (CoreBluetooth en iOS, API de Bluetooth de Android) conectada a través de canales de plataforma.
La latencia total del pipeline (voz → ASR → traducción → transmisión → visualización) es de aproximadamente 1 segundo. La UI en Dart usa visualización optimista (muestra "traduciendo..." inmediatamente al enviar) para que la conversación se sienta ágil.
Cifras
- Idiomas: 108 en total (61 ML + 47 IA)
- Idiomas ASR: 30 con reconocimiento de voz en dispositivo
- Idiomas OCR: 92 con reconocimiento de texto por cámara
- Tamaño base de la app: ~150 MB + modelos descargables
- Plataformas: iOS + Android desde una única base de código Flutter
- Código Dart/Flutter: ~60% del total (UI, estado, enrutamiento, lógica de negocio)
- Código nativo: ~40% (ASR, LLM, OCR, Bluetooth, superposiciones, gestión de memoria)
- Tamaño del equipo: 1
Lo Que Flutter Hizo Bien en Este Proyecto
Una sola base de código para UI compleja. Cinco superficies de funciones, múltiples modos cada una, hojas de descarga, tour de incorporación, layouts adaptativos — escribir esto una vez en lugar de dos veces fue la diferencia entre publicar la app y no hacerlo como desarrollador en solitario.
Los canales de plataforma están bien diseñados. El puente entre el código Dart y el nativo es limpio, bien documentado y fiable. Para una app donde el cómputo pesado es nativo pero la experiencia de usuario es Flutter, esta es exactamente la arquitectura correcta.
Recarga en caliente para iteración rápida. Ajustar layouts, probar estados, iterar flujos de UX — la recarga en caliente redujo el tiempo de iteración de minutos a segundos a lo largo de cientos de cambios en la UI.
El ecosistema es maduro. Gestión de estado (Riverpod), navegación, localización (117 locales), diseño adaptable — el ecosistema Flutter tiene soluciones de calidad de producción para todo esto.
Lo Que Fue Difícil
La presión de memoria es el punto ciego de Flutter. Flutter no expone control de memoria de grano fino. Cuando co-cargas múltiples modelos de ML nativos junto al motor de Flutter, necesitas gestionar la memoria a nivel nativo y exponerla de vuelta a Dart. No existe una API integrada de Flutter para "cuánta RAM está usando mi app" o "cuál es la presión de memoria del sistema".
Ciclo de vida de la superposición nativa. Las superposiciones flotantes que operan fuera de la superficie Flutter son arquitectónicamente complejas. La actividad Flutter puede estar en segundo plano mientras la superposición está activa. Mantener el puente vivo, gestionar la sincronización de estado y manejar eventos de ciclo de vida específicos de cada plataforma requirió un código nativo significativo que Flutter no puede abstraer.
Complejidad de compilación en iOS. CocoaPods con pods de script ML Kit, entitlements (increased-memory-limit para co-cargar ASR + LLM), temporización de App Tracking Transparency, firma de código — el pipeline de compilación de iOS tiene muchas piezas en movimiento que las herramientas de Flutter no gestionan completamente.
Pruébala
Traverba es gratuita en ambas plataformas. Voz, cámara, traducción de pantalla y traducción de texto son completamente gratuitas y sin límites. Premium ($1.99/mes) desbloquea el chat grupal, la transcripción de archivos y los resúmenes de reuniones.
Disponible en Google Play y App Store. Más información en traverba.com.
Estoy disponible para responder preguntas sobre la arquitectura, los patrones de integración Flutter + nativo, o la IA en dispositivo en general.