Desarrollo de apps Flutter BLE

Publicado el 9 de abril de 2026

16 min de lectura
Companion app Flutter BLE conectada a hardware de ciclismo
Jonas Ockerman
Jonas OckermanCo-Founder

Tienes un producto de hardware y necesitas una app que lo acompañe. En la superficie parece sencillo. Pero en cuanto entra en juego Bluetooth Low Energy, el alcance crece de formas que no se ven venir hasta que llevas tres meses metido.

Lo aprendimos construyendo la companion app de Classified Cycling, una empresa belga que fabrica tecnología de transmisión inalámbrica para ciclistas. Su hardware se conecta por BLE, necesita actualizaciones de firmware over-the-air y funciona en exteriores, donde el Bluetooth se comporta de forma impredecible. Hoy la app gestiona conexiones con cuatro tipos de hardware distintos, se integra con dos ecosistemas de socios externos y distribuye el firmware de todos ellos. Lo que empezó como “una pantalla de emparejamiento y unos ajustes” acabó siendo una plataforma de conectividad completa.

Este artículo cubre qué exigen realmente las companion apps BLE, por qué Flutter las resuelve bien, dónde está la complejidad de verdad y qué preguntas conviene hacerse antes de empezar.

Qué hacen realmente las companion apps BLE

Una companion app es la interfaz móvil de un dispositivo de hardware. Para la mayoría de productos, eso significa cuatro cosas:

Emparejamiento y descubrimiento de dispositivos. La app escanea los periféricos BLE cercanos, identifica el dispositivo correcto (normalmente por datos de advertising propios del fabricante), se autentica y guarda el bond. En iOS, el sistema gestiona el estado de bonding. En Android lo gestionas tú. Se comportan de forma lo bastante distinta como para ser, en la práctica, dos problemas de ingeniería separados.

Configuración. Una vez emparejada, la app lee y escribe valores de configuración en characteristics BLE. En Classified Cycling eso significa la asignación de botones del cambio, los modos de ruta y los umbrales de cambio de marcha. Cada parámetro configurable es una characteristic GATT con su UUID, su tipo de datos y sus permisos de lectura y escritura.

Telemetría en vivo. Algunos dispositivos emiten datos de forma continua. El hub de Classified envía nivel de batería, estado de conexión y eventos de cambio como notificaciones BLE. La app se suscribe a esas characteristics y actualiza la interfaz en tiempo real. La dificultad está en hacerlo de forma fiable mientras el móvil va en el bolsillo del maillot, el hub va en el cuadro de la bici y entre ambos hay un pelotón de fibra de carbono y metal.

Actualizaciones de firmware OTA. Es la parte más dura. Enviar firmware por BLE significa transferir varios cientos de kilobytes por un canal lento y con pérdidas, de una manera que no pueda dejar inservible el dispositivo si se interrumpe. La mayoría del hardware usa el protocolo Device Firmware Update de Nordic Semiconductor (Nordic DFU) o similar. La app orquesta la transferencia, gestiona los reintentos y debe recuperarse con elegancia si la conexión cae a mitad de la actualización.

Quién define el panorama BLE sobre el que construyen los equipos
Nordic Semiconductor
DFU y chips presentes en incontables periféricos
Apple Core Bluetooth
Bonding en iOS, modos en segundo plano y reglas de la store
Stack Bluetooth de Android
Límites de escaneo, permisos y políticas de energía de cada OEM

Por qué Flutter funciona para BLE

El ecosistema BLE de Flutter se ha consolidado en torno a dos paquetes bien mantenidos: flutter_reactive_ble y flutter_blue_plus. Ambos cubren el ciclo de vida completo de una conexión. Ambos soportan iOS y Android desde una sola base de código.

Ese detalle de la base de código única pesa más de lo que parece. BLE diverge entre iOS y Android ya a nivel de sistema operativo. Si construyes apps nativas separadas, escribes y mantienes dos stacks BLE distintos. Con Flutter escribes la capa BLE una vez y absorbes las diferencias de plataforma en una capa acotada, en lugar de repartirlas entre dos bases de código.

El ecosistema de plugins también es maduro para casos de uso concretos. Nordic DFU tiene un paquete Flutter bien soportado. Detección de iBeacon, perfiles GATT para categorías de hardware habituales, gestión del escaneo en segundo plano: son problemas resueltos con paquetes mantenidos, no cosas que construyas desde cero.

Para quien decide: Flutter para BLE significa un solo equipo, una sola base de código y un ecosistema con suficiente profundidad para cubrir de entrada la mayoría de requisitos de una companion app. La alternativa realista, equipos nativos de iOS y Android separados, cuesta más y tarda más para un resultado funcionalmente equivalente.

Stacks BLE de Flutter frente a dos bases de código nativas
flutter_reactive_ble
API orientada a streams
Una capa Dart
Base de código
iOS + Android
Plataformas
Las pipelines reactivas encajan con tu app
Mejor cuando
flutter_blue_plus
Alternativa muy extendida
Una capa Dart
Base de código
iOS + Android
Plataformas
El estilo de callbacks encaja con el equipo
Mejor cuando
Nativo iOS + Android
Implementaciones separadas
BLE en Swift + Kotlin
Base de código
Lógica duplicada
Plataformas
Restricciones legacy fuera de Flutter
Mejor cuando

Dónde vive la complejidad de verdad

La pantalla de emparejamiento es la parte fácil. Esto es lo que de verdad lleva tiempo.

iOS y Android hacen el bonding de forma distinta. iOS gestiona el bonding BLE a nivel de sistema. Android lo expone a nivel de app. En iOS, si el usuario reinstala la app, el sistema sigue recordando el bond pero el identificador de dispositivo guardado por la app ha desaparecido, así que la app no encuentra sus propios dispositivos emparejados sin volver a escanear. En Android gestionas el bonding tú. Estos casos límite requieren tratamiento explícito.

Condiciones Bluetooth en exteriores. La app de Classified funciona sobre bicicletas. El móvil va en el bolsillo del maillot, el hub debajo del sillín y el ciclista se mueve a 40 km/h por un campo de carbono y metal. La señal BLE no se propaga de forma fiable en esas condiciones. La app necesita lógica de reconexión automática, monitorización de la calidad de la conexión y una máquina de estados que distinga entre “desconectado temporalmente” y “el usuario se ha ido”.

El ciclo de vida de una conexión BLE. Una conexión BLE no es un socket. Tiene estados: escaneo, conexión, descubrimiento de servicios, autenticación, lectura de characteristics, recepción de notificaciones y desconexión. Cada estado puede fallar, y la recuperación es distinta en cada caso. Gestionarlo bien exige una máquina de estados explícita, no una serie de callbacks. Así es el ciclo de vida en Classified:

01Escanear periféricos que coincidan con el prefijo de fabricante del dispositivo
02Conectar y descubrir servicios y characteristics GATT
03Autenticar con un handshake de desafío-respuesta sobre una characteristic cifrada
04Suscribirse a las characteristics de notificación para telemetría y estado
05Leer y escribir characteristics de configuración según interactúa el usuario
06Al desconectar, determinar si lo inició el usuario o fue una caída, y actuar en consecuencia

Procesamiento en segundo plano. Tanto iOS como Android restringen lo que una app puede hacer en segundo plano. Si la app debe mantener una conexión BLE con la pantalla apagada, algo habitual en apps de fitness y ciclismo, hay que gestionar los modos de ejecución en segundo plano de forma explícita. Los modos en segundo plano de Core Bluetooth en iOS exigen declarar capabilities y limitan lo que puedes leer. Las restricciones de escaneo en segundo plano de Android se endurecieron en Android 8 y otra vez en Android 12.

Isolates de Dart para los bucles de escaneo. Escanear BLE de forma continua desde el isolate principal de Dart penaliza el rendimiento de la interfaz. El patrón correcto es ejecutar el bucle de escaneo en un isolate de Dart aparte y devolver los resultados al isolate de UI mediante paso de mensajes. Es el mismo patrón que usamos para operaciones nativas bloqueantes en nuestro trabajo con Flutter FFI.

La ventana de la actualización de firmware. Una actualización OTA tarda de 2 a 5 minutos en un enlace BLE típico. Durante ese tiempo la app no puede perder la conexión, la batería del móvil no puede agotarse y el sistema no puede interrumpir la operación. Eso no es un problema de interfaz, es ingeniería de fiabilidad.

Nada de esto es insalvable. Pero cada punto exige ingeniería deliberada, y el tiempo se acumula. Si tu equipo no ha entregado nunca una companion app BLE, la estimación de “la capa BLE” está probablemente entre un 40 y un 60 % por debajo de lo que debería.

App BLE frente a interfaz web

No todo dispositivo conectado necesita una companion app nativa. Web Bluetooth existe y funciona en navegadores basados en Chromium. Un panel web puede cubrir la configuración y la visualización de estado en muchos casos de uso. Así se elige:

RequisitoApp nativaWeb Bluetooth / panel web
Actualizaciones de firmware OTASíLimitado (solo transferencia de archivo)
Conexión BLE en segundo planoSíNo
Soporte de iOSSíNo (Apple bloquea Web BLE en iOS)
Uso sin conexiónSíParcial
Distribución en app storeObligatoriaNo hace falta
Notificaciones pushSíLimitado
Perfiles GATT complejosSíSí
Rapidez de la primera versiónMás lentoMás rápido

Web Bluetooth solo funciona en Chrome y Edge. En iOS no funciona en absoluto. Si tus usuarios están en iPhone, una interfaz web no sustituye del todo a una app.

Para casos de uso limitados a configuración, en los que Android es tu única plataforma y los usuarios son lo bastante técnicos como para usar un navegador, Web Bluetooth es razonable. En cuanto entran iOS, la conectividad en segundo plano, las actualizaciones OTA o la distribución al consumidor, necesitas una app nativa.

Elige una app nativa cuando
Necesitas actualizaciones de firmware OTA con reintentos y recuperación sólidos
El producto debe seguir conectado en segundo plano con la pantalla apagada
Tus usuarios están en iPhone o necesitas distribución por la App Store
Las notificaciones push o un flujo de instalación de consumo importan para la adopción
Web Bluetooth puede bastar cuando
Solo se trata de configuración en Android, con usuarios técnicos en Chrome o Edge
Las sesiones son cortas y la pestaña puede quedarse abierta, sin enlace en segundo plano
Optimizas para la primera versión más rápida y el alcance solo en navegador es aceptable

Qué preguntar antes de empezar

Estas son las preguntas que hacemos en cada llamada de discovery de un proyecto de companion app BLE. Si vas a encargar uno, tener respuestas claras antes de empezar ahorra tiempo y evita sorpresas de alcance.

¿Cuántos tipos de dispositivo? Cada tipo de dispositivo es una implementación BLE aparte. Un hub, un sensor y un mando que hay que gestionar desde una sola app son tres stacks de conexión, no uno.

¿Qué perfiles BLE usáis? Los perfiles GATT estándar (Heart Rate, Battery, Device Information) tienen paquetes Flutter ya existentes. Los perfiles propietarios exigen trabajo de implementación del protocolo. El protocolo D-Fly de Shimano, por ejemplo, nos obligó a implementar su secuencia de emparejamiento propietaria desde cero. Lo detallamos en el artículo sobre la integración con Shimano DI2.

¿Hacen falta actualizaciones de firmware OTA? Eso duplica la complejidad de la capa BLE. No es una metáfora. La lógica de reintentos, la orquestación de la transferencia y la recuperación para OTA suponen aproximadamente tanto esfuerzo de ingeniería como todo lo demás junto.

¿La app debe mantener una conexión BLE en segundo plano? Si es así, suma la gestión de los modos de ejecución en segundo plano en ambas plataformas, más pruebas en toda la gama de variantes de fabricantes Android (Samsung, Xiaomi y Huawei implementan la optimización de batería de forma distinta).

¿Cómo es el uso en exteriores? Los escenarios de electrónica de consumo (instalación en casa, configuración ocasional) tienen requisitos de fiabilidad muy distintos de los escenarios de deporte y fitness (movimiento constante, señal variable, en algunos casos crítico para la seguridad).

¿Hay requisitos regulatorios? Los dispositivos médicos, los que interactúan con sistemas críticos para la seguridad y los que se venden en categorías reguladas (automoción, aviación, medicina) tienen exigencias de certificación que afectan a la implementación BLE.

¿Cómo se reparten las plataformas objetivo? Si el 80 % de tus usuarios está en iOS, eso cambia la priorización. Si necesitas soporte de Android 8, eso determina qué APIs están disponibles. Si tienes que lanzar en ambas plataformas en tres meses, el tamaño del equipo y el alcance deben reflejarlo.

Conclusiones clave

La app de Classified empezó como una pantalla de emparejamiento. Cuatro años y varias generaciones de hardware después, gestiona conexiones con cuatro tipos de dispositivo, se integra con dos ecosistemas de socios y funciona en condiciones para las que la mayoría del código de conectividad nunca se diseñó. Esa trayectoria es lo habitual.

Las companion apps BLE no son apps que casualmente usan Bluetooth. La capa de conectividad es el producto. Diséñala y constrúyela así desde el principio.

La ventaja de la base de código única de Flutter es real en proyectos BLE. La consolidación del ecosistema de librerías y poder compartir la lógica de conexión entre iOS y Android reducen de forma apreciable el coste de mantenimiento continuo.

Las actualizaciones de firmware OTA no son una funcionalidad para el final. Si hacen falta, entran en el alcance desde el principio. Las decisiones de arquitectura que hacen segura la OTA son difíciles de añadir después.

Las preguntas de la sección anterior no son exhaustivas, pero cualquier equipo que no sepa responderlas con claridad antes de empezar descubrirá su alcance a mitad de proyecto. Las llamadas de discovery existen por algo.

Si estás formando un equipo que ha migrado desde React Native, la historia de BLE en Flutter es una de las victorias más claras. Profundizamos en esa decisión de migración en nuestro artículo sobre la migración de React Native a Flutter. Si BLE es tu motor principal, Flutter es la elección correcta y la migración merece la inversión.

El ecosistema de Flutter va más allá de BLE. Si también estás evaluando Flutter para e-commerce, por ejemplo flujos scan-to-order con escáneres de códigos de barras Bluetooth, nuestro artículo sobre la integración de Flutter con Magento explica cómo se cruzan ambos patrones.

¿Necesitas ayuda con el desarrollo de una app BLE?

Preguntas frecuentes