Flutter vs React Native
Comparamos en todos los aspectos el Flutter de Google, basado en Dart, con el React Native de Meta, basado en JavaScript/TypeScript. ¿Qué framework multiplataforma destaca en 2025?
Framework RN gestionado que se instala con Node.js LTS y es reversible gracias a CNG
Instalación núcleo de React Native que da control total sobre el toolchain nativo
En 2026, la respuesta predeterminada es Expo + CNG: como expo prebuild regenera las carpetas nativas, el "eject" dejó de ser una puerta de un solo sentido, el sistema de config plugins cubre la mayor parte de la configuración nativa y el plan gratuito de EAS Build es suficiente para proyectos pequeños-medianos. Las razones que justifican Bare React Native son limitadas pero reales: un toolchain personalizado no soportado por EAS, la obligatoriedad de un CI on-prem o un SDK nativo muy poco común. Si ninguna de las tres aplica, empieza con Expo.
| Categoría | Expo | Bare React Native |
|---|---|---|
| Rendimiento | 8/10 | 8/10 |
| Facilidad de aprendizaje | 9/10 | 6/10 |
| Ecosistema | 8/10 | 8/10 |
| Comunidad | 8/10 | 8/10 |
| Mercado laboral | 7/10 | 8/10 |
| A prueba de futuro | 8/10 | 7/10 |
expo prebuild) las carpetas nativas se pueden regenerar — el "eject" ya no es una puerta de un solo sentidoprebuild --cleanios/android son permanentes; cada actualización de versión exige aplicar el diff a mano con Upgrade Helperexpo-updates manualmente o montar una alternativa// Expo — agregar un permiso nativo con app.config.ts + un config plugin local (TypeScript)
// plugins/withCameraUsage.ts — config plugin que añade el permiso de cámara a Info.plist
import { ConfigPlugin, withInfoPlist } from "expo/config-plugins";
const withCameraUsage: ConfigPlugin = (config) =>
withInfoPlist(config, (config) => {
config.modResults.NSCameraUsageDescription =
"We need camera access to take a profile photo";
return config;
});
export default withCameraUsage;
// app.config.ts — el plugin se referencia por RUTA de archivo (requiere npm i -D tsx)
import "tsx/cjs";
import { ExpoConfig, ConfigContext } from "expo/config";
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: "MyApp",
slug: "my-app",
version: "1.0.0",
plugins: [["./plugins/withCameraUsage.ts"], "expo-router", "expo-updates"],
updates: { url: "https://u.expo.dev/your-project-id" },
runtimeVersion: { policy: "appVersion" },
});
// Terminal: genera las carpetas nativas (CNG) y aplícalas
// npx expo prebuild --clean
// Ejecuta EAS Build y publica la actualización OTA
// eas build --platform all --profile production
// eas update --branch production --message "Bug fix: login crash"// Bare React Native — instalación de un paquete + configuración nativa a mano (TypeScript)
// 1) Instala el paquete: autolinking lo enlaza, descarga los pods, recompila
// $ npm install react-native-vision-camera react-native-nitro-modules react-native-nitro-image
// $ npx pod-install
// $ npm run ios # Android: npm run android
// 2) Añade los permisos A MANO — este paso no está incluido en el autolinking
// ios/MyApp/Info.plist:
// <key>NSCameraUsageDescription</key>
// <string>Profil fotoğrafı çekmek için kameraya erişim gerekiyor</string>
// android/app/src/main/AndroidManifest.xml:
// <uses-permission android:name="android.permission.CAMERA" />
// 3) Uso en el lado de JS (código compartido)
import React, { useEffect } from "react";
import { Camera, useCameraPermission } from "react-native-vision-camera";
function ProfileCamera() {
const { hasPermission, requestPermission } = useCameraPermission();
useEffect(() => {
if (!hasPermission) requestPermission();
}, [hasPermission, requestPermission]);
return <Camera style={{ flex: 1 }} isActive={true} device="back" />;
}
export default ProfileCamera;
// 4) Actualización de versión (0.86 -> 0.87): esto NO tiene un comando de CLI
// Upgrade Helper (web): https://react-native-community.github.io/upgrade-helper/
// -> aplica el diff a mano en Podfile.lock, build.gradle, AppDelegate.swift
// 5) Tu propio pipeline de CI (GitHub Actions, resumen)
// - run: npx pod-install
// - run: xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration ReleaseEn 2026, la respuesta predeterminada es Expo + CNG: como expo prebuild regenera las carpetas nativas, el "eject" dejó de ser una puerta de un solo sentido, el sistema de config plugins cubre la mayor parte de la configuración nativa y el plan gratuito de EAS Build es suficiente para proyectos pequeños-medianos. Las razones que justifican Bare React Native son limitadas pero reales: un toolchain personalizado no soportado por EAS, la obligatoriedad de un CI on-prem o un SDK nativo muy poco común. Si ninguna de las tres aplica, empieza con Expo.
En 2026, la respuesta predeterminada es Expo + CNG: el sistema de config plugins cubre la mayoría de los módulos nativos, el plan gratuito de EAS Build (15+15 builds/mes) es suficiente para proyectos pequeños-medianos, y gracias a expo prebuild bajar a código nativo ya no es una decisión irreversible. Las razones reales que justifican bare RN: un toolchain personalizado no soportado por EAS, la obligatoriedad de un CI on-prem corporativo, o un SDK nativo muy poco común que no puede cubrirse con un config plugin.