Serie React Native y BLE: Parte 1 - Construyendo un framework BLE para iOS

He estado trabajando en desarrollo móvil tanto en proyectos nativos como en plataformas cruzadas (React Native, Flutter), y también tengo experiencia trabajando con BLE. A veces recibo correos electrónicos preguntando sobre la comunicación de RN/Flutter con BLE. Por eso, decidí introducir esta serie React Native y BLE para guiarte sobre cómo desarrollar un framework BLE nativo y conectarlo a React Native.
Por supuesto, habrá otra serie para Flutter y BLE después de terminar la serie de React Native.
En esta serie, te guiaré a través de un proceso completo desde el desarrollo hasta la distribución.
- Crear un framework iOS / Android.
- Script para construir y distribuir tu framework.
- Importar los frameworks a tu proyecto React Native.
- Usar tu framework nativo en React Native.
- Distribuir tu aplicación.
- Y otras cosas interesantes que quiero compartir contigo…
Si te gusta lo que hago, considera apoyarme en buy a coffee for Uy Nguyen :)
Vamos.
Xcode 13, iOS 15, Swift 5, React 17.0.1, React Native 0.64.1.
Preparar el framework iOS
El primer paso es crear un framework BLE. Tampoco tienes que crear un framework, puedes incluir tu código fuente dentro del proyecto iOS directamente si lo deseas.
Sin embargo, la razón por la que recomiendo mover toda la lógica BLE a un framework es que es reutilizable, puedes compartir tu framework con otros proyectos como Flutter o proyectos Nativos sin tener que duplicar la lógica.
Otra razón es que mejorará el tiempo de compilación de Xcode, dividir tu aplicación en varios frameworks puede acelerar los tiempos de construcción. Esto es porque el sistema de construcción de Xcode no tiene que recompilar frameworks para los cuales los archivos Swift no han cambiado.
Desde la barra superior izquierda de Xcode, selecciona File > New > Project > Desde la sección "Framework & Library", selecciona "Framework" > Ingresa el nombre de tu framework (yo uso "BLEFramework")

Ahora, puedes desarrollar tu lógica BLE en el proyecto que acabas de crear. No voy a detallar la implementación de todos los métodos individuales del framework ya que depende de tu lógica de negocio y tu arquitectura. Puedes encontrar mis tutoriales anteriores para tener una idea de cómo implementar un framework BLE. Bluetooth Low Energy OniOS, Play Central And Peripheral Roles With CoreBluetooth
Tomaré un método simple en mi framework BLE como ejemplo: el método startScanning.
1 | /** |
OK ahora tenemos un framework BLE, pasemos al siguiente paso: Construir y distribuir tu framework.
Construir y distribuir
Hay muchas formas de distribuir un framework como usar CocoaPod, o manualmente enviando un archivo compilado, etc. En esta publicación, te proporcionaré un script para convertir tu framework en un framework universal que oculta toda tu lógica, y puede usarse tanto para dispositivos físicos como simuladores.
Asegúrate de activar la bandera “Build Libraries for Distribution” en “Build Settings” a YES. La bandera indica que el compilador debe generar una de las interfaces estables para que el framework pueda usarse cuando se lancen versiones más nuevas de Xcode o el compilador Swift.

A continuación, crea un archivo bash, ponlo en la raíz de la carpeta ios, y copia los siguientes comandos al archivo. Luego ejecuta el script.
1 | ### SCRIPT TO BUILD A SWIFT UNIVERSAL FRAMEWORK |
Una vez que ejecutes el script exitosamente, deberías ver el resultado como se muestra a continuación

Donde:
YOUR_TARGET_NAME.xcframework: El framework universal que puede usarse tanto para dispositivos físicos como simuladores.- carpeta device: contiene
YOUR_TARGET_NAME.frameworkque solo puede usarse en dispositivos físicos. - carpeta simulator: contiene
YOUR_TARGET_NAME.frameworkque solo puede usarse en simuladores.
Ahora tenemos un framework BLE para nuestra aplicación, pasemos al siguiente paso - Crear un nuevo proyecto React Native.
Inicializar proyecto React Native
Para crear un proyecto React Native sin usar Expo (recomiendo no usar Expo porque vamos a agregar mucho código Nativo para Android e iOS a nuestro proyecto, para más detalles puedes consultar what is the difference between expo and react native), abre el terminal y escribe
1 | react-native init projectName |
Espera un momento para configurar tu proyecto. Después de ejecutar exitosamente, deberías ver la estructura de carpetas como se muestra a continuación:
1 | |---projectName |
Abre el archivo projectName.xcworkspace, configuraremos el código nativo en el siguiente paso.
Conectándolos
Primero, arrastra y suelta el YOUR_TARGET_NAME.xcframework a tu espacio de trabajo de Xcode.
Como mi SDK está construido en Swift, voy a crear una clase Swift como puente para que podamos comunicarnos desde el SDK a React Native.
Desde el proyecto Xcode, selecciona File > New > File > Swift File > Ingresa el nombre de tu archivo (ej. BLEManager) > Add. Aparecerá un diálogo preguntando si quieres crear un bridging header, selecciona sí.
Para aquellos que no saben para qué se usa el bridging header, el bridging header es donde defines todas las clases Objective-C que están expuestas a Swift.

Para usar clases RCT, asegúrate de hacer #import de todos los headers relacionados a tu ...-Bridging-Header.h. De lo contrario, obtendrás errores de compilación.
1 | #import <React/RCTBridgeModule.h> |
A continuación, agrega la interfaz RCTEventEmitter a la clase BLEManager que acabamos de crear en el paso anterior.
1 | (BLEManager) <--- Remember to add this [1] |
[1] Asegúrate de decorar tu clase y funciones con la palabra clave @objc para asegurar que la clase y funciones se exporten correctamente al runtime de Objective-C.
[2] Una vez que se descubre un periférico, envía un evento a Javascript.
[3] Registra el soporte de eventos del módulo nativo.
Finalmente, para exponer los métodos de tu módulo nativo, crea un nuevo archivo BLEManager.m y agrega el siguiente código.
1 | @interface RCT_EXTERN_MODULE(BLEManager, RCTViewManager) |
Eso es todo. Javascript ahora puede invocar la función startScanning y escuchar el evento didFoundDeviceEvent.
Pruebas
Es hora de probar nuestra implementación, React Native proporciona instancias NativeEventEmitter y NativeModules que te permiten trabajar con módulos nativos.
Desde la carpeta raíz, abre App.js e importa las cosas necesarias.
1 | import { |
En el método componentDidMount, agrega lo siguiente
1 | componentDidMount() { |
[1] Crea una nueva instancia de NativeEventEmitter y escucha el evento didFoundDevice [2]
[3] Porque aún no soportamos el evento de cambios de estado de Bluetooth, temporalmente retrasamos 3s antes de llamar al escaneo solo para asegurar que el Bluetooth está encendido. Lo mejoraremos más tarde soportando más eventos y métodos.
OK, vamos a construir y ejecutar tu proyecto. Si ves tu consola de log imprimiendo los resultados del proceso de escaneo, felicitaciones, ¡lo hiciste bien!
Siguiente paso
En esta publicación, te mostré cómo crear un framework BLE y cómo usar un módulo nativo BLE en un proyecto React Native como invocar un método desde Javascript a Swift y manejar un evento desde Swift a Javascript. En el siguiente tutorial, haremos lo mismo en la plataforma Android.
Si enfrentas algún problema, no dudes en contactarme. Me encantaría ayudar.
Felices fiestas.