Concepto clave
Los Expo Modules son paquetes de código nativo que extienden las capacidades de tu aplicación Expo, permitiendo acceder a APIs del sistema operativo que no están disponibles en JavaScript puro. Piensa en ellos como traductores especializados: tu aplicación en JavaScript necesita comunicarse con el hardware del dispositivo (como la cámara o sensores), y los Expo Modules actúan como intermediarios que convierten esas solicitudes en instrucciones que iOS o Android pueden entender directamente.
En el desarrollo avanzado, crear tus propios módulos es crucial cuando necesitas funcionalidades específicas que no existen en la comunidad, como integrar con hardware personalizado o APIs empresariales privadas. A diferencia de los métodos tradicionales que requieren configurar proyectos nativos separados, Expo Modules usa una arquitectura unificada con Expo CLI y config plugins, lo que simplifica el mantenimiento y despliegue. Imagina construir una aplicación de fitness que use un sensor de frecuencia cardíaca Bluetooth exclusivo: sin un módulo personalizado, sería imposible acceder a esos datos desde JavaScript.
Cómo funciona en la práctica
Para crear un Expo Module, sigues un flujo estructurado que garantiza compatibilidad entre plataformas. Primero, defines la interfaz JavaScript que usarás en tu código React Native, luego implementas la lógica nativa en Swift/Objective-C para iOS y Kotlin/Java para Android, y finalmente configuras el módulo para que Expo lo reconozca. Aquí un ejemplo paso a paso para un módulo simple que muestra un mensaje nativo:
- Inicia un nuevo proyecto de módulo con
npx create-expo-module, que genera la estructura básica con carpetas para iOS, Android y JavaScript. - En la carpeta
src, escribe el archivo JavaScript que exporta las funciones que quieres exponer, comoshowMessage(text). - En
ios/MyModule.swift, implementa la función nativa que usa APIs de iOS para mostrar una alerta con el texto recibido. - En
android/src/main/java/.../MyModule.kt, haz lo mismo para Android usando Toast o Snackbar. - Registra el módulo en los archivos de configuración de Expo (
expo-module.config.json) para que se incluya automáticamente al construir la aplicación.
Este proceso asegura que tu módulo funcione en ambas plataformas sin que tú gestiones manualmente las diferencias, similar a como un framework como React Native abstrae la UI nativa.
Código en acción
Veamos un ejemplo funcional de un Expo Module que obtiene el nivel de batería del dispositivo. Este es un caso común en aplicaciones que necesitan optimizar el rendimiento en dispositivos móviles.
Antes: Sin un módulo, tendrías que usar soluciones limitadas o bibliotecas de terceros que podrían no ser confiables.
Después: Con tu propio módulo, tienes control total y rendimiento nativo. Aquí está el código JavaScript:
// En tu aplicación Expo, importa y usa el módulo
import * as BatteryModule from 'expo-battery-module';
async function checkBattery() {
try {
const batteryLevel = await BatteryModule.getBatteryLevel();
console.log(`Nivel de batería: ${batteryLevel}%`);
return batteryLevel;
} catch (error) {
console.error('Error al obtener batería:', error);
}
}
// Llama a la función en tu componente
checkBattery();Y aquí la implementación nativa para Android (Kotlin):
// android/src/main/java/expo/modules/battery/BatteryModule.kt
package expo.modules.battery
import android.content.Context
import android.os.BatteryManager
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class BatteryModule : Module() {
override fun definition() = ModuleDefinition {
Name("BatteryModule")
AsyncFunction("getBatteryLevel") {
val batteryManager = appContext.reactContext?.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
batteryLevel.toDouble() / 100.0 // Devuelve un valor entre 0 y 1
}
}
}Errores comunes
- No probar en ambas plataformas: Implementar solo para iOS u Android y asumir que funciona en la otra. Solución: Usa el emulador y dispositivos reales para verificar el comportamiento, y escribe pruebas unitarias específicas para cada plataforma.
- Olvidar registrar el módulo en la configuración de Expo: Si no actualizas
expo-module.config.json, Expo no incluirá tu módulo en la build. Solución: Revisa siempre este archivo después de añadir nuevas funciones o plataformas. - Manejo incorrecto de hilos en código nativo: Ejecutar operaciones bloqueantes en el hilo principal de UI, causando que la aplicación se congele. Solución: Usa
AsyncFunctionen Kotlin o colas de despacho en Swift para operaciones asíncronas. - No versionar el módulo adecuadamente: Cambiar APIs sin incrementar la versión, rompiendo aplicaciones existentes. Solución: Sigue versionado semántico (ej., 1.0.0 a 1.1.0 para nuevas características) y documenta los cambios.
- Ignorar el manejo de permisos: Acceder a APIs sensibles como ubicación sin solicitar permisos, lo que causa fallos en iOS/Android. Solución: Añade configuraciones de permisos en
app.jsony verifica en tiempo de ejecución.
Checklist de dominio
- Creé un Expo Module desde cero usando
npx create-expo-moduley lo integré en una aplicación Expo existente. - Implementé funciones nativas en Swift/Kotlin que exponen APIs del dispositivo a JavaScript.
- Probé el módulo en emuladores de iOS y Android, verificando que no haya crashes o warnings.
- Configuré permisos necesarios en
app.jsonpara APIs sensibles y manejé errores de usuario. - Documenté el módulo con ejemplos de uso y lo publiqué en un repositorio privado o npm.
- Optimicé el rendimiento usando operaciones asíncronas y evité fugas de memoria en código nativo.
- Actualicé el módulo siguiendo versionado semántico y manteniendo retrocompatibilidad.
Crear un módulo para controlar el brillo de pantalla
En este ejercicio, desarrollarás un Expo Module que permita ajustar el brillo de la pantalla del dispositivo desde tu aplicación Expo. Esto es útil para aplicaciones como lectores o reproductores de video que necesitan controlar la experiencia visual del usuario.
- Prepara el entorno: Asegúrate de tener Expo CLI instalado y un proyecto Expo existente. Ejecuta
npx create-expo-module expo-brightness-controlen una carpeta separada para generar la estructura del módulo. - Define la interfaz JavaScript: En
src/index.ts, exporta dos funciones:setBrightness(level: number)para establecer el brillo (0 a 1) ygetBrightness(): Promise<number>para obtener el nivel actual. - Implementa para iOS: En
ios/ExpoBrightnessControl.swift, usaUIScreen.main.brightnesspara ajustar y obtener el brillo. Asegúrate de manejar los límites (0.0 a 1.0). - Implementa para Android: En
android/src/main/java/expo/modules/brightness/ExpoBrightnessControl.kt, usaWindowManager.LayoutParams.screenBrightnesscon el contexto de la actividad. Nota: En Android, necesitas permisos si cambias la configuración del sistema. - Configura el módulo: Actualiza
expo-module.config.jsonpara incluir el nombre y plataformas. Añade cualquier permiso necesario en la secciónandroidoios. - Integra en tu aplicación: En tu proyecto Expo, añade el módulo localmente usando
expo install ./ruta/a/expo-brightness-controly crea un componente simple con controles deslizantes para probarlo. - Prueba y depura: Ejecuta la aplicación en un emulador iOS y Android. Verifica que los cambios de brillo se reflejen y que no haya errores en la consola.
- Usa
AsyncFunctionen Kotlin paragetBrightnessya que accede a hardware. - En iOS, recuerda que
UIScreen.main.brightnesses una propiedad mutable que puedes asignar directamente. - Para permisos en Android, añade
<uses-permission android:name="android.permission.WRITE_SETTINGS" />en el manifest si es necesario, pero prueba primero sin él ya que algunos niveles no lo requieren.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.