[{"data":1,"prerenderedAt":28},["ShallowReactive",2],{"articolo-gestire-ambienti-multipli-in-flutter-con-i-flavors-dev-staging-e-produzione":3,"comments-article-gestire-ambienti-multipli-in-flutter-con-i-flavors-dev-staging-e-produzione":27},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},63,"Gestire ambienti multipli in Flutter con i Flavors: dev, staging e produzione","gestire-ambienti-multipli-in-flutter-con-i-flavors-dev-staging-e-produzione","Impara a configurare build separate per sviluppo, staging e produzione in Flutter usando i flavor su Android e le configuration su iOS, con nomi, icone e endpoint differenti.","## Perché servono ambienti multipli\n\nQuando un'app Flutter cresce, è indispensabile poter distinguere tra diversi ambienti di esecuzione: **sviluppo** (dev), **staging** (collaudo) e **produzione** (prod). Ogni ambiente ha tipicamente:\n\n- Un endpoint API differente (`api.dev.miaapp.com` vs `api.miaapp.com`)\n- Un `applicationId` \u002F bundle identifier diverso, così da installare più versioni sullo stesso dispositivo\n- Nomi e icone distinti per riconoscere a colpo d'occhio quale build stai usando\n- Chiavi di analytics o crash reporting separate\n\nIn Flutter questa separazione si ottiene combinando i **flavor** nativi (Android) e le **build configuration\u002Fscheme** (iOS) con una configurazione a livello Dart tramite gli **entry point** e i **dart-define**.\n\n## Configurare i flavor su Android\n\nApri `android\u002Fapp\u002Fbuild.gradle` e aggiungi i `productFlavors` all'interno del blocco `android`:\n\n```gradle\nandroid {\n    \u002F\u002F ...\n    flavorDimensions \"env\"\n\n    productFlavors {\n        dev {\n            dimension \"env\"\n            applicationIdSuffix \".dev\"\n            resValue \"string\", \"app_name\", \"MiaApp Dev\"\n        }\n        staging {\n            dimension \"env\"\n            applicationIdSuffix \".staging\"\n            resValue \"string\", \"app_name\", \"MiaApp Staging\"\n        }\n        prod {\n            dimension \"env\"\n            resValue \"string\", \"app_name\", \"MiaApp\"\n        }\n    }\n}\n```\n\nNel `AndroidManifest.xml` usa la risorsa dinamica per il nome dell'app:\n\n```xml\n\u003Capplication\n    android:label=\"@string\u002Fapp_name\"\n    ... >\n```\n\nGrazie all'`applicationIdSuffix` potrai avere `com.miaazienda.miaapp.dev`, `.staging` e la versione di produzione installate contemporaneamente.\n\n## Configurare le scheme su iOS\n\nSu iOS il processo è più manuale. In Xcode:\n\n1. Duplica la configurazione `Debug`, `Release` e `Profile` per ogni ambiente (es. `Debug-dev`, `Release-prod`, ecc.).\n2. Crea uno **Scheme** per ogni flavor tramite *Product > Scheme > Manage Schemes*.\n3. Definisci una *User-Defined Setting* (es. `APP_NAME` e `BUNDLE_SUFFIX`) e usala nel `Info.plist` con `$(APP_NAME)`.\n\nImposta il `PRODUCT_BUNDLE_IDENTIFIER` di ogni configurazione, ad esempio `com.miaazienda.miaapp.dev` per l'ambiente di sviluppo.\n\n## Gli entry point Dart\n\nCrea un file di configurazione condiviso e più `main` distinti. Prima definiamo la configurazione:\n\n```dart\n\u002F\u002F lib\u002Fconfig\u002Fapp_config.dart\nenum Environment { dev, staging, prod }\n\nclass AppConfig {\n  final Environment environment;\n  final String apiBaseUrl;\n  final String appName;\n\n  const AppConfig({\n    required this.environment,\n    required this.apiBaseUrl,\n    required this.appName,\n  });\n\n  static late AppConfig instance;\n}\n```\n\nOra gli entry point, uno per ambiente:\n\n```dart\n\u002F\u002F lib\u002Fmain_dev.dart\nimport 'package:flutter\u002Fmaterial.dart';\nimport 'config\u002Fapp_config.dart';\nimport 'app.dart';\n\nvoid main() {\n  AppConfig.instance = const AppConfig(\n    environment: Environment.dev,\n    apiBaseUrl: 'https:\u002F\u002Fapi.dev.miaapp.com',\n    appName: 'MiaApp Dev',\n  );\n  runApp(const MyApp());\n}\n```\n\n```dart\n\u002F\u002F lib\u002Fmain_prod.dart\nimport 'package:flutter\u002Fmaterial.dart';\nimport 'config\u002Fapp_config.dart';\nimport 'app.dart';\n\nvoid main() {\n  AppConfig.instance = const AppConfig(\n    environment: Environment.prod,\n    apiBaseUrl: 'https:\u002F\u002Fapi.miaapp.com',\n    appName: 'MiaApp',\n  );\n  runApp(const MyApp());\n}\n```\n\nNel resto del codice accedi alla configurazione tramite `AppConfig.instance.apiBaseUrl`.\n\n## Eseguire e compilare i flavor\n\nPer avviare o compilare un flavor specifico usa i flag `--flavor` e `--target`:\n\n```bash\n# Avvio in sviluppo\nflutter run --flavor dev --target lib\u002Fmain_dev.dart\n\n# Build di produzione (Android)\nflutter build appbundle --flavor prod --target lib\u002Fmain_prod.dart\n\n# Build iOS di staging\nflutter build ipa --flavor staging --target lib\u002Fmain_staging.dart\n```\n\n## Alternativa: --dart-define\n\nSe preferisci evitare più file `main`, puoi passare variabili a compile-time con `--dart-define`:\n\n```bash\nflutter run --dart-define=ENV=dev --dart-define=API_URL=https:\u002F\u002Fapi.dev.miaapp.com\n```\n\nE leggerle in Dart:\n\n```dart\nconst env = String.fromEnvironment('ENV', defaultValue: 'dev');\nconst apiUrl = String.fromEnvironment('API_URL');\n```\n\nPer gestire molte variabili conviene usare un file JSON con `--dart-define-from-file=config\u002Fdev.json`, supportato dalle versioni recenti di Flutter.\n\n## Automatizzare con la configurazione dell'IDE\n\nIn VS Code definisci le configurazioni in `.vscode\u002Flaunch.json`:\n\n```json\n{\n  \"configurations\": [\n    {\n      \"name\": \"Dev\",\n      \"request\": \"launch\",\n      \"type\": \"dart\",\n      \"program\": \"lib\u002Fmain_dev.dart\",\n      \"args\": [\"--flavor\", \"dev\"]\n    },\n    {\n      \"name\": \"Prod\",\n      \"request\": \"launch\",\n      \"type\": \"dart\",\n      \"program\": \"lib\u002Fmain_prod.dart\",\n      \"args\": [\"--flavor\", \"prod\"]\n    }\n  ]\n}\n```\n\n## Best practice\n\n- **Non committare segreti**: mantieni chiavi API e credenziali fuori dal repository, usando file di configurazione ignorati o secret manager della CI.\n- **Un solo punto di verità**: centralizza la configurazione in `AppConfig` invece di sparpagliare condizioni `if (env == ...)` nel codice.\n- **Icone differenti**: usa `flutter_launcher_icons` con override per flavor per generare icone diverse e riconoscere subito la build.\n- **Integra la CI\u002FCD**: parametrizza i job di build in base al flavor per generare artifact separati per ogni ambiente.\n\n## Conclusione\n\nI flavor sono la soluzione standard per gestire ambienti multipli in Flutter. Con una configurazione iniziale ben strutturata — flavor nativi, entry point Dart e una classe `AppConfig` centralizzata — potrai passare da sviluppo a produzione con un solo comando, riducendo errori e velocizzando il ciclo di rilascio.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F20850dac-3fce-4ef9-a617-30ca6118e8e4.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1750714270076-0f168ceb040a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMTU4MzZ8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Shekai","https:\u002F\u002Funsplash.com\u002F@shekai","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fcolorful-houses-with-open-doors-and-windows-plFvBrbRXIY",null,"published","2026-08-11T04:00:42+00:00","Flavors in Flutter: gestire dev, staging e produzione","Guida pratica ai flavor in Flutter: configura ambienti dev, staging e produzione con endpoint, nomi e icone diversi su Android e iOS.",{"id":21,"name":22,"slug":23},3,"Best practice","best-practice",{"id":25,"name":26},1,"Flutter Bot",[],1789120588113]