[{"data":1,"prerenderedAt":27},["ShallowReactive",2],{"articolo-icone-e-splash-screen-nativi-in-flutter-con-flutter-launcher-icons-e-flutter-native-splash":3,"comments-article-icone-e-splash-screen-nativi-in-flutter-con-flutter-launcher-icons-e-flutter-native-splash":26},{"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},95,"Icone e splash screen nativi in Flutter con flutter_launcher_icons e flutter_native_splash","icone-e-splash-screen-nativi-in-flutter-con-flutter-launcher-icons-e-flutter-native-splash","La prima impressione di un'app si gioca sull'icona e sulla schermata di avvio. Vediamo come generare icone adattive, icone monocromatiche Android 13 e splash screen conformi alle API Android 12+ con due pacchetti ormai standard.","## Perché icona e splash non sono un dettaglio\n\nQuando pubblichiamo un'app Flutter, l'utente vede due cose prima ancora del nostro primo widget: l'icona nel launcher e la schermata di avvio nativa. Sono elementi che vivono **fuori** dal framework Flutter: risiedono nelle cartelle `android\u002F` e `ios\u002F`, sono gestiti dal sistema operativo e richiedono decine di asset in risoluzioni diverse.\n\nGenerarli a mano significa produrre manualmente `mipmap-hdpi`, `mipmap-xxxhdpi`, `Assets.xcassets\u002FAppIcon.appiconset` con una ventina di PNG, più i file per web, Windows e macOS. Due pacchetti risolvono il problema in pochi secondi: **flutter_launcher_icons** e **flutter_native_splash**.\n\nIn questa guida vediamo la configurazione completa, incluse le parti che spesso vengono dimenticate: le *adaptive icons*, l'icona monocromatica per i temi dinamici di Android 13+, le API di splash screen introdotte da Android 12 e la gestione dei flavor.\n\n## Preparare gli asset sorgente\n\nPrima di configurare qualsiasi cosa, servono immagini sorgente di buona qualità:\n\n- **Icona**: un PNG quadrato di almeno **1024x1024 px**, senza angoli arrotondati (li applica il sistema) e senza canale alpha per iOS.\n- **Foreground adattivo Android**: un PNG **1024x1024** in cui il contenuto visibile occupa al massimo il **66% centrale**. Android ritaglia l'icona in forme diverse (cerchio, squircle, goccia) e tutto ciò che esce dalla *safe zone* viene tagliato.\n- **Splash**: un logo PNG con sfondo trasparente, tipicamente **1152x1152 px** per la versione Android 12+.\n\nUna struttura tipica del progetto:\n\n```\nassets\u002F\n  branding\u002F\n    icon.png                 # 1024x1024, opaco\n    icon_foreground.png      # 1024x1024, trasparente, safe zone 66%\n    icon_monochrome.png      # 1024x1024, silhouette bianca su trasparente\n    splash_logo.png\n    splash_logo_dark.png\n```\n\n## flutter_launcher_icons: generare le icone\n\nAggiungiamo il pacchetto tra le dipendenze di sviluppo:\n\n```yaml\ndev_dependencies:\n  flutter_launcher_icons: ^0.14.1\n```\n\nLa configurazione può stare direttamente in `pubspec.yaml` oppure, come consiglio, in un file separato `flutter_launcher_icons.yaml` per non appesantire il pubspec:\n\n```yaml\n# flutter_launcher_icons.yaml\nflutter_launcher_icons:\n  image_path: \"assets\u002Fbranding\u002Ficon.png\"\n\n  android: \"ic_launcher\"\n  adaptive_icon_background: \"#0B1F3A\"\n  adaptive_icon_foreground: \"assets\u002Fbranding\u002Ficon_foreground.png\"\n  adaptive_icon_monochrome: \"assets\u002Fbranding\u002Ficon_monochrome.png\"\n  min_sdk_android: 23\n\n  ios: true\n  remove_alpha_ios: true\n  background_color_ios: \"#0B1F3A\"\n\n  web:\n    generate: true\n    image_path: \"assets\u002Fbranding\u002Ficon.png\"\n    background_color: \"#0B1F3A\"\n    theme_color: \"#0B1F3A\"\n\n  windows:\n    generate: true\n    icon_size: 256\n\n  macos:\n    generate: true\n```\n\nGenerazione:\n\n```bash\ndart run flutter_launcher_icons -f flutter_launcher_icons.yaml\n```\n\n### Cosa succede sotto il cofano\n\n- Su Android vengono creati i `mipmap-*` e, se sono presenti `adaptive_icon_*`, i file XML in `res\u002Fmipmap-anydpi-v26\u002Fic_launcher.xml` che descrivono i layer background\u002Fforeground\u002Fmonochrome.\n- Su iOS viene riempito `Runner\u002FAssets.xcassets\u002FAppIcon.appiconset` con tutte le dimensioni richieste. `remove_alpha_ios: true` è **obbligatorio**: App Store Connect rifiuta le icone con canale alpha.\n- Su web viene aggiornato anche `web\u002Fmanifest.json` con le icone PWA.\n\n### L'icona monocromatica (Android 13+)\n\nCon i *themed icons*, Android colora l'icona in base al wallpaper dell'utente usando il layer `monochrome`. Se non lo forniamo, il sistema mostra l'icona standard: nessun crash, ma l'app stona in una home screen tematizzata.\n\nLa regola per il file monocromatico: una **silhouette piena**, bianca su sfondo trasparente, senza gradienti né testo sottile. Anche qui vale la safe zone del 66%.\n\n## flutter_native_splash: la schermata di avvio\n\n```yaml\ndev_dependencies:\n  flutter_native_splash: ^2.4.3\n```\n\nDa Android 12 la splash screen non è più un semplice `windowBackground`: il sistema usa la **SplashScreen API**, che mostra l'icona dell'app al centro di uno sfondo a tinta unita, con vincoli precisi sulle dimensioni. Per questo il pacchetto prevede una sezione dedicata `android_12`.\n\n```yaml\n# flutter_native_splash.yaml\nflutter_native_splash:\n  color: \"#FFFFFF\"\n  image: assets\u002Fbranding\u002Fsplash_logo.png\n\n  color_dark: \"#0B1F3A\"\n  image_dark: assets\u002Fbranding\u002Fsplash_logo_dark.png\n\n  android_12:\n    image: assets\u002Fbranding\u002Fsplash_logo.png\n    icon_background_color: \"#FFFFFF\"\n    image_dark: assets\u002Fbranding\u002Fsplash_logo_dark.png\n    icon_background_color_dark: \"#0B1F3A\"\n\n  android: true\n  ios: true\n  web: false\n\n  android_gravity: center\n  ios_content_mode: center\n  fullscreen: false\n```\n\nGenerazione e, se serve, ripristino:\n\n```bash\ndart run flutter_native_splash:create --path=flutter_native_splash.yaml\n\n# per rimuovere tutto ciò che è stato generato\ndart run flutter_native_splash:remove\n```\n\n### I vincoli di Android 12+\n\nQuesto è il punto in cui la maggior parte dei team sbaglia:\n\n- L'immagine viene mostrata dentro un cerchio di **160 dp** di diametro; con `icon_background_color` l'area utile del logo scende a circa **2\u002F3** di quel cerchio.\n- Non esiste più il concetto di splash a schermo intero con immagine di sfondo: se passiamo un banner rettangolare, verrà ritagliato e apparirà sgranato.\n- Il branding testuale va messo **nell'app**, non nella splash nativa.\n\nLa regola pratica: usare un **logo semplice, centrato e vettorialmente pulito**, e replicare eventuali elementi di brand nella prima schermata Flutter.\n\n## Tenere la splash visibile durante l'inizializzazione\n\nIl problema classico: la splash nativa sparisce appena il motore Flutter è pronto, ma l'app deve ancora caricare token, preferenze o dati remoti. Il risultato è un flash bianco seguito da uno spinner.\n\nIl pacchetto espone due API per evitarlo:\n\n```dart\nimport 'package:flutter\u002Fwidgets.dart';\nimport 'package:flutter_native_splash\u002Fflutter_native_splash.dart';\n\nFuture\u003Cvoid> main() async {\n  final binding = WidgetsFlutterBinding.ensureInitialized();\n\n  \u002F\u002F Blocca la rimozione automatica della splash nativa.\n  FlutterNativeSplash.preserve(widgetsBinding: binding);\n\n  await _bootstrap();\n\n  runApp(const MyApp());\n}\n\nFuture\u003Cvoid> _bootstrap() async {\n  \u002F\u002F Esempio: preferenze, sessione utente, remote config...\n  await Future.wait([\n    SessionRepository.instance.restore(),\n    RemoteConfigService.instance.init(),\n  ]);\n}\n```\n\nLa rimozione va fatta **dopo il primo frame utile**, non dentro `main()`, altrimenti si torna al flash iniziale:\n\n```dart\nclass MyApp extends StatefulWidget {\n  const MyApp({super.key});\n\n  @override\n  State\u003CMyApp> createState() => _MyAppState();\n}\n\nclass _MyAppState extends State\u003CMyApp> {\n  @override\n  void initState() {\n    super.initState();\n    WidgetsBinding.instance.addPostFrameCallback((_) {\n      FlutterNativeSplash.remove();\n    });\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Demo',\n      home: const HomePage(),\n    );\n  }\n}\n```\n\n> **Attenzione**: se `preserve()` viene chiamato e per un errore (eccezione durante il bootstrap) `remove()` non viene mai invocato, l'app resta bloccata sulla splash. Conviene proteggere l'inizializzazione con un `try\u002Ffinally` o, meglio, rimuovere la splash in ogni caso e mostrare l'errore nell'interfaccia Flutter.\n\n```dart\nFuture\u003Cvoid> main() async {\n  final binding = WidgetsFlutterBinding.ensureInitialized();\n  FlutterNativeSplash.preserve(widgetsBinding: binding);\n\n  BootstrapResult result;\n  try {\n    await _bootstrap();\n    result = BootstrapResult.ok();\n  } catch (e, s) {\n    result = BootstrapResult.error(e, s);\n  }\n\n  runApp(MyApp(bootstrap: result));\n}\n```\n\n## Una transizione fluida tra splash nativa e UI\n\nPer evitare uno stacco brusco, un trucco efficace è replicare in Flutter la stessa composizione della splash nativa (stesso colore di sfondo, stesso logo, stessa posizione) e poi animare la transizione verso la home:\n\n```dart\nclass SplashGate extends StatelessWidget {\n  const SplashGate({super.key, required this.ready, required this.child});\n\n  final bool ready;\n  final Widget child;\n\n  @override\n  Widget build(BuildContext context) {\n    return AnimatedSwitcher(\n      duration: const Duration(milliseconds: 350),\n      child: ready\n          ? child\n          : const ColoredBox(\n              key: ValueKey('splash'),\n              color: Color(0xFFFFFFFF),\n              child: Center(\n                child: SizedBox(\n                  width: 120,\n                  height: 120,\n                  child: Image(\n                    image: AssetImage('assets\u002Fbranding\u002Fsplash_logo.png'),\n                  ),\n                ),\n              ),\n            ),\n    );\n  }\n}\n```\n\nL'utente percepisce una sola schermata continua invece di due passaggi distinti.\n\n## Gestire i flavor\n\nSe l'app ha più ambienti (dev, staging, produzione) con icone diverse, entrambi i pacchetti supportano file di configurazione multipli.\n\nPer le icone, il naming è convenzionale: `flutter_launcher_icons-\u003Cflavor>.yaml`.\n\n```\nflutter_launcher_icons-dev.yaml\nflutter_launcher_icons-staging.yaml\nflutter_launcher_icons-prod.yaml\n```\n\n```bash\ndart run flutter_launcher_icons   # genera tutti i flavor trovati\n```\n\nPer la splash, si passa esplicitamente il flavor:\n\n```bash\ndart run flutter_native_splash:create --flavor dev\ndart run flutter_native_splash:create --flavor prod\n```\n\nUn banner \"DEV\" sull'icona di sviluppo evita l'errore classico di provare una build sbagliata credendola quella di produzione.\n\n## Automatizzare con uno script\n\nPer non dover ricordare i comandi, conviene definirli una volta sola. Con `melos` o con un semplice script shell:\n\n```bash\n#!\u002Fusr\u002Fbin\u002Fenv bash\nset -e\n\necho \"→ Generazione icone...\"\ndart run flutter_launcher_icons\n\necho \"→ Generazione splash screen...\"\ndart run flutter_native_splash:create\n\necho \"✓ Asset nativi aggiornati\"\n```\n\nIn alternativa, con `melos`:\n\n```yaml\n# melos.yaml\nscripts:\n  branding:\n    run: |\n      dart run flutter_launcher_icons && \\\n      dart run flutter_native_splash:create\n    description: Rigenera icone e splash screen nativi\n```\n\n### Va committato il codice generato?\n\nSì. I file generati finiscono in `android\u002Fapp\u002Fsrc\u002Fmain\u002Fres` e `ios\u002FRunner\u002FAssets.xcassets`, che sono cartelle sotto controllo di versione. Committarli garantisce che la CI produca build corrette senza dover eseguire i generatori a ogni pipeline. Il generatore va rilanciato solo quando cambiano gli asset di brand.\n\n## Problemi frequenti e soluzioni\n\n| Sintomo | Causa probabile | Soluzione |\n|---|---|---|\n| Icona vecchia dopo la rigenerazione | Cache del launcher Android | Disinstallare l'app e reinstallare, oppure `flutter clean` |\n| App Store rifiuta l'icona | Canale alpha presente | `remove_alpha_ios: true` e ricontrollo del PNG sorgente |\n| Logo tagliato su Android 12+ | Immagine fuori dalla safe zone | Ridurre il contenuto a circa 2\u002F3 del canvas |\n| Splash bianca poi flash scuro | Mancata configurazione dark mode | Impostare `color_dark` e `image_dark` |\n| App bloccata sulla splash | `preserve()` senza `remove()` | Rimozione in `addPostFrameCallback` e gestione delle eccezioni |\n| Icona adattiva con bordi strani | Foreground opaco a tutto schermo | Usare un PNG con sfondo trasparente |\n\n## Checklist finale prima della pubblicazione\n\n- [ ] Icona testata su launcher **circolare e squircle** (Pixel e Samsung si comportano diversamente).\n- [ ] Icona monocromatica verificata con i temi dinamici attivi su Android 13+.\n- [ ] Splash controllata in **light e dark mode**.\n- [ ] Nessun flash bianco tra splash nativa e primo frame Flutter.\n- [ ] Icone generate anche per web\u002Fdesktop se le piattaforme sono supportate.\n- [ ] Flavor con icone distinguibili tra loro.\n- [ ] Asset generati committati nel repository.\n\n## Conclusioni\n\nIcone e splash screen sono fra le attività più rapide da automatizzare e fra le più trascurate. Con una configurazione di venti righe e due comandi otteniamo asset coerenti su tutte le piattaforme, conformi alle linee guida di Android 12+ e alle regole di validazione dell'App Store.\n\nIl punto chiave da ricordare è che la splash nativa non è il posto giusto per il branding elaborato: serve a coprire i millisecondi di avvio del motore Flutter. Tutto il resto — animazioni, claim, transizioni — va costruito dentro l'app, dove abbiamo il pieno controllo del rendering.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002Fc0852808-c90b-499f-9b20-da50790ba6dd.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1710993012000-f109972e3b8f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODkxODU2OTN8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Solen Feyissa","https:\u002F\u002Funsplash.com\u002F@solenfeyissa","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-close-up-of-a-cell-phone-with-icons-on-it-m06dRiQAy9M",null,"published","2026-09-12T04:01:33+00:00","Icone e splash screen nativi in Flutter: guida pratica","Come generare icone adattive, icone monocromatiche Android 13 e splash screen conformi ad Android 12+ in Flutter con flutter_launcher_icons e native_splash.",{"id":21,"name":22,"slug":23},1,"Guide","guide",{"id":21,"name":25},"Flutter Bot",[],1789205501385]