Flavors dev, staging y prod en Flutter: ejercicio resuelto
Flavors dev, staging y prod en Flutter: ejercicio resuelto
Ninguna app de producción real tiene un solo entorno. Flavors (o variantes de build) permiten ejecutar la misma base de código con configuraciones distintas sin un solo if en la lógica de negocio. La forma más portable en Flutter es usar --dart-define o --dart-define-from-file.
Enunciado
Configura tres entornos — dev, staging y prod — con:
- URL de API distinta por entorno.
- Nombre de app diferenciado (visible en el lanzador del dispositivo).
- Logging habilitado solo en
dev. - Una pantalla que muestre la configuración activa.
Enfoque recomendado: dart-define-from-file
Crea un archivo JSON por entorno (no los versiones con secretos):
Añade envs/ al .gitignore si contienen secretos (o usa variables de entorno en CI).
Solución: AppConfig
Solución: Logger condicional
Solución: main.dart y pantalla de info
Cómo ejecutar cada entorno
Integración con VS Code (launch.json)
Resultado esperado
flutter run --dart-define-from-file=envs/dev.json→ pantalla naranja con “DEV” y URL de dev.flutter run --dart-define-from-file=envs/prod.json→ pantalla verde con “PROD”, logging desactivado.- Sin pasar el flag → fallback a valores de dev (safe default).
Errores frecuentes
- Leer
String.fromEnvironmenten tiempo de ejecución conconst: estos valores se resuelven en tiempo de compilación; si cambias eljsontienes que recompilar, no basta con hot reload. - Versionar archivos con secretos: usa
.gitignorepara los archivos.jsoncon credenciales reales; en CI inyéctalos como variables de entorno o secretos del runner. - Cambiar nombre de app solo en Dart: el nombre visible en el lanzador del dispositivo se configura en
AndroidManifest.xml(Android) eInfo.plist(iOS). Usa herramientas comoflutter_launcher_nameo configura manualmente.
Alternativa: native flavors (Android/iOS)
Para cambios más profundos (íconos de app distintos, targets de Xcode separados), necesitas native flavors en Gradle y Xcode. --dart-define-from-file cubre el 80% de los casos con mucho menos configuración.
Aplicación práctica
Es la primera cosa que configuras en un proyecto nuevo de producción, junto a la arquitectura base. Impide que se produzcan llamadas a producción desde una build de desarrollo y facilita el QA.
Siguiente ejercicio recomendado
- Arquitectura por capas en Flutter: ejercicio resuelto
- Inyección de dependencias con get_it en Flutter: ejercicio resuelto
- Dio con interceptores en Flutter: ejercicio resuelto
- Todos los ejercicios de Flutter
Práctica guiada y siguiente paso
- Más ejercicios de Flutter
- Ejercicios C para reforzar fundamentos
- Programación en C en 100 ejercicios resueltos
- Ver el libro en Amazon (incluido en Kindle Unlimited)
- Suscribirte a la newsletter
FAQ
¿dart-define reemplaza completamente los native flavors?
Para la mayoría de apps, sí. Los native flavors son necesarios si quieres íconos distintos, bundle IDs separados o configuraciones nativas por entorno en Android/iOS.
¿Los valores de dart-define son seguros para secretos de API?
No completamente. Están embebidos en el binario y son extraíbles con herramientas de análisis. Para secretos sensibles usa un servidor intermedio o servicios como Firebase Remote Config.
¿Funciona con GitHub Actions?
Sí. Pasa los valores como variables de entorno en el workflow y genera el JSON de entorno dinámicamente antes del build: echo '{"API_BASE_URL":"${{ secrets.API_URL }}"}' > envs/prod.json.