Reglas de Módulos Nativos
Cuándo escribir código nativo versus usar un paquete Expo SDK. Estas reglas mantienen a los equipos en el camino soportado para Expo SDK 57 y React Native 0.86, minimizan sorpresas de CNG/prebuild y garantizan que las dependencias nativas se envíen con dev-client y binarios de tienda coincidentes.
- Revisa Tier 1 antes de añadir cualquier paquete npm con código nativo - una dependencia incorrecta fuerza una reconstrucción de dev-client y puede bloquear Expo Go completamente.
- Aplica Tiers 2-3 al integrar plugins de configuración o escribir módulos nativos personalizados - los errores corrompen
ios/ y android/ en cada prebuild.
- Ejecuta Tier 4 antes de fusionar cambios nativos - CI debe probar que prebuild es reproducible y la compilación de New Architecture aún compila.
- Todo módulo nativo personalizado necesita un ADR con un propietario nombrado - el código nativo huérfano se vuelve indeleble.
- Empareja con
npx expo-doctor después de cada cambio de dependencia nativa.
-
Busca paquetes de Expo SDK primero: expo-camera, expo-location, expo-notifications y más de 100 módulos se envían con binarios nativos de SDK 57 - prefierelos sobre envolturas nativas random de npm.
- Instala:
npx expo install expo-camera - no npm install expo-camera@latest.
- Verifica: El paquete aparece en los docs de Expo para SDK 57 antes de adoptarlo.
-
Segunda opción: módulo comunitario con plugin de configuración de Expo: Muchas librerías incluyen un plugin de configuración en el array plugins de app.config - lee su matriz de compatibilidad con SDK 57 antes de instalar.
- Verifica: Issues de GitHub para soporte de RN 0.86 y New Architecture.
- Rechaza: Módulos no mantenidos actualizados por última vez para SDK 49.
-
Tercera opción: Expo Modules API para puentes nativos personalizados delgados: Cuando no existe un paquete, escribe un módulo Expo en modules/my-feature/ - autolinking e integración de tipos TypeScript se conectan limpiamente con CNG.
- Plantilla:
npx create-expo-module@latest para la estructura del módulo.
- ADR requerido: Documenta por qué los paquetes SDK fueron insuficientes.
-
Último recurso: parches Swift/Kotlin desnudos vía plugin de configuración: Las carpetas ios/ y android/ mantenidas manualmente son solo para brownfield - las aplicaciones de CNG estándar expresan cambios como plugins.
- Brownfield: El ADR explica por qué CNG no se usa.
- Rechaza: Ediciones de "arreglo rápido" al
Podfile que no están codificadas en un plugin.
-
Expo Go no es un objetivo de prueba nativa para módulos personalizados: Los paquetes no incluidos en Expo Go requieren expo-dev-client - no reclames aprobación de QA solo desde Expo Go.
- CI: El perfil
development de EAS compila clientes dev instalables.
- Onboarding: README indica limitaciones de Expo Go el primer día.
-
Un cambio nativo por PR cuando sea posible: Mezclar un nuevo SDK de pago, plugin de cámara y módulo personalizado en una fusión hace que bisect sea imposible cuando prebuild falla.
- Reversión: Los PRs de propósito único se mapean limpiamente a decisiones de reversión de tienda y OTA.
- Revisión: Los cambios nativos obtienen un revisor dedicado con experiencia en plataformas móviles.
-
Siempre npx expo install para deps nativos: Resuelve versiones compatibles con binarios nativos de SDK 57 - el éxito de compilación no garantiza estabilidad en tiempo de ejecución.
- Después de SDK bump:
npx expo install --fix luego expo-doctor.
- CI: Falla si los rangos de
package.json se desvían de las versiones incluidas de Expo sin ADR.
-
Registra plugins de configuración en app.config.ts: Los permisos nativos, entitlements y entradas de manifest pertenecen en plugins - no en ediciones manuales posteriores a prebuild.
- Orden: El orden del plugin importa cuando múltiples plugins tocan el mismo archivo - documenta el orden en comentarios.
- Inspecciona:
npx expo prebuild --clean localmente antes de fusionar cambios de plugin.
-
Escribe plugins de configuración idempotentes: Ejecutar prebuild dos veces no debe duplicar entradas en Info.plist o AndroidManifest.xml.
- Prueba: Ejecuta prebuild dos veces y
git diff la salida nativa - debería estar vacía la segunda vez.
- Rechaza: Plugins de append regex sin verificaciones de existencia.
-
Declara permisos con strings visibles para el usuario: iOS NSCameraUsageDescription y rationale de permiso de Android - strings faltantes causan crash o rechazo de revisión de tienda.
- Fuente: Plugin o
app.config ios.infoPlist - nunca solo en archivos generados.
- Localización: Planifica
locales/ para strings de permisos en idiomas enviados.
-
Usa expo-build-properties para compilar SDK y objetivos de despliegue: Centraliza minSdkVersion, compileSdkVersion y objetivo de despliegue de iOS - ediciones de Gradle dispersas se pierden en prebuild.
- Valores por defecto de SDK 57: Comienza desde valores por defecto de Expo; anula solo con necesidad medida.
- ADR: Documenta por qué la versión mínima de OS fue elevada.
-
Autolinking maneja la mayoría de enlaces - no edites manualmente settings.gradle: Expo autolinking registra módulos nativos - hacks de pod install manual pertenecen en plugins si es realmente necesario.
- Debug:
npx expo-modules-autolinking resolve cuando un módulo no se encuentra.
- Monorepo: Asegura una instancia
react-native - copias duplicadas rompen autolinking silenciosamente.
-
Gitignore generado ios/ y android/ bajo CNG: Las carpetas nativas comprometidas bloquean actualizaciones de plantilla de SDK 57 - EAS Build ejecuta prebuild remotamente.
- Debug local:
npx expo prebuild --clean reproduce proyectos nativos de CI.
- Excepción: Brownfield ADR con estrategia de fusión para directorios nativos.
-
Reconstruye dev client después de cada cambio de dependencia nativa: OTA (eas update) actualiza solo JavaScript - nuevos módulos nativos requieren eas build --profile development.
- Comunica: Publica en #mobile cuando la URL de dev client cambia - shells obsoletos causan errores engañosos de "module not found".
- Versión: Bump
expo-dev-client con actualizaciones de SDK.
-
Las compilaciones de tienda y cambios nativos nunca son solo OTA: Si una característica de JS requiere un nuevo módulo nativo, envía una compilación de tienda primero - controla JS con comprobaciones de versión en tiempo de ejecución hasta que se alcance el umbral de adopción.
- Patrón: Política de versión en tiempo de ejecución
expo-updates + feature flag para nueva API nativa.
- Ver: Release & OTA Rules.
-
Prueba en dispositivos físicos para módulos de hardware: Cámara, BLE, NFC y push se comportan diferentemente en simuladores - QA solo en sim pierde fallas de permiso y background.
- Matriz: Documenta lista mínima de dispositivos por módulo nativo (ej., Android 10 mid-tier, iPhone SE).
- CI: Maestro en artefactos de vista previa de EAS, no Expo Go.
-
La compatibilidad de New Architecture es explícita: RN 0.86 favorece New Architecture - verifica que módulos nativos de terceros declaren soporte de Fabric/TurboModule o documenta fallback.
- Verifica: README de librería y advertencias de
expo-doctor.
- ADR: Registra módulos que requieren Old Architecture hasta que correcciones upstream se implementen.
-
Libera handles y listeners nativos: Instancias de SharedObject de larga vida desde módulos Expo (players, sensors) necesitan release() en unmount - las fugas crashean apps en background.
- Patrón: Limpieza
useEffect llama al módulo remove() o suscripción remove().
- Profile: Xcode Instruments / Android Profiler para fugas de módulos nativos antes de lanzamiento.
-
Los módulos Expo personalizados viven en modules/ con API de JS tipada: Exporta una superficie TypeScript estrecha - las features importan @/modules/my-feature, no strings raw de NativeModules.
- Pruebas: Mock en el límite del módulo en Jest; E2E en dispositivo para integración.
- Docs: README en carpeta de módulo con matriz de soporte de plataforma.
-
Sin lógica de negocio en código nativo: La capa nativa maneja APIs de plataforma y marshaling - reglas de precios y validación permanecen en TypeScript.
- Olor: Swift
if user.isPremium duplicado desde JS.
- Arregla: Pasa primitivos a través del bridge; mantén una fuente única de verdad en JS.
-
Semantic versioning para módulos internos: Los cambios de API nativa que rompen requieren una compilación de tienda y changelog - trata modules/ como un paquete publicado.
- Coordina: Skew de versión de JS y nativo es imposible en un bundle - envía juntos.
- Monorepo: Los módulos internos aún obtienen entradas de CHANGELOG.
-
Revisión de seguridad para módulos nativos que tocan secretos: Wrappers de Keychain, SDKs de pago y librerías de attestation necesitan aprobación de seguridad - no solo revisión de mobile lead.
-
Prebuild en CI en PRs nativos: Ejecuta npx expo prebuild --clean --no-install (o compilación EAS completa) para atrapar fallos de plugin antes de fusión.
- Cache: Las compilaciones remotas de EAS son aceptables cuando prebuild local es lento.
- Artefacto: Adjunta resumen de diff de prebuild a PR para el revisor.
-
ADR para todo módulo nativo personalizado y dependencia nativa no-Expo: Status, propietario, alternativas consideradas, posición de New Architecture y trigger de jubilación.
- Tier 1 (1-6): Camino de integración - elegir tier incorrecto cuesta semanas de mantenimiento nativo.
- Tier 2 (7-12): Instala y plugins - arregla prebuild antes de que desarrolladores descarguen dev clients rotos.
- Tier 3 (13-18): Flujo de CNG - asegura que binarios coincidan con expectativas de JavaScript.
- Tier 4 (19-24): Gobernanza - previene acumulación de deuda nativa.
Módulo Expo vs módulo nativo React Native?
Prefiere Expo Modules API para nuevos puentes personalizados - autolinking, TypeScript e integración de plugins de configuración con CNG. Los módulos nativos RN heredados funcionan pero necesitan más mantenimiento de enlace manual en SDK 57.
¿Cuándo es aceptable editar manualmente ios/?
Aplicaciones Brownfield con directorios nativos comprometidos y una estrategia de fusión documentada. Las aplicaciones Expo greenfield estándar nunca deben editar manualmente archivos generados - usa plugins de configuración.
¿Necesito reconstruir después de añadir un plugin de configuración?
Sí - los plugins mutan proyectos nativos en tiempo de prebuild. Ejecuta un nuevo dev-client y compilación de tienda; OTA solo es insuficiente.
¿Cómo sé si un paquete funciona con Expo Go?
Verifica docs de Expo - si el paquete no está en el bundle de Expo Go, necesitas un dev build. expo-doctor también puede advertir sobre dependencias incompatibles.
¿Puedo enviar un módulo nativo vía OTA?
No - el código nativo se envía en el binario. Puedes enviar JS que llame a un módulo nativo existente OTA, pero añadir el módulo en sí requiere una compilación de tienda.
¿Cuál es el punto de entrada de Expo Modules API?
Crea un módulo con npx create-expo-module@latest, regístralo en el package.json workspaces o carpeta modules/ de la app, y autolinking lo detecta en prebuild.
¿Cómo comparten monorepos módulos nativos?
Coloca módulos compartidos en packages/native-feature/ con react-native peer deps apropiados. Una app ejecuta prebuild; el módulo autolinks desde la ruta del workspace que Metro resuelve.
¿Rompe New Architecture módulos nativos más antiguos?
Algunos módulos comunitarios atrasan soporte de Fabric/TurboModule en RN 0.86. Verifica antes de adoptar; documenta fallback de Old Architecture en un ADR si es requerido temporalmente.
¿Cuándo debo forjar una dependencia nativa?
Casi nunca - upstream una corrección o envuelve con un plugin de configuración. Forks cuando el mantenedor se fue requieren un ADR con propiedad de parche de seguridad.
¿Cómo pruebo módulos nativos en Jest?
Mock en el límite de TypeScript (jest.mock('@/modules/my-feature')) con formas de retorno realistas. Ejecuta pruebas de integración en dispositivo vía Maestro o QA manual para caminos de hardware.
¿Qué dispara expo prebuild --clean?
Actualizaciones de SDK, cambios de plugin, fallos de autolinking y errores de compilación nativa inexplicables. --clean es la ruta de recuperación por defecto en SDK 57 - no un último recurso.
¿Pueden ejecutarse plugins de configuración solo en EAS Build?
Los plugins se ejecutan en cualquier prebuild - local y remoto. Mantén prebuild local reproducible para que CI y laptops generen proyectos nativos idénticos.
¿Quién es propietario del mantenimiento de módulos nativos?
El ADR nombra un propietario primario (iOS/Android o mobile full-stack). El código nativo sin propietario es un bloqueador de fusión en equipos maduros.
Versiones de stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (expo ~57.0.4).