Skip to Content
FlutterLezione 6 Pubblicazione Nei Market6.1 Preparazione e build (teoria)

1. Controlli Preliminari

Obiettivo:

Assicurarsi che l’ambiente di sviluppo e il codice siano in uno stato ideale per una build affidabile, priva di errori e pronta per il rilascio.


1.1 Aggiornamento delle dipendenze

  • Verifica outdated:
flutter pub outdated # Elenca i pacchetti non aggiornati flutter pub upgrade # Aggiorna all’ultima versione consentita
  • Pulizia cache:
flutter clean flutter pub get
  • Lockfile coerente:
  • Controlla il file pubspec.lock per garantire che tutte le versioni siano bloccate correttamente.

1.2 Analisi del codice e testing

  • Static code analysis:
flutter analyze # Rileva errori, warning e problemi di stile
  • Unit & widget test:
flutter test # Esegue tutti i test definiti

Tip: integra analisi e test nella CI per fail-fast su PR.

1.3 Rimozione del debug e logging

  • Rimuovi tutti i print() e logger di debug non configurabili a runtime.
  • Disabilita banner di debug in MaterialApp:
MaterialApp( debugShowCheckedModeBanner: false, )

1.4 Configurazione dei metadati dell’app Flutter

  • pubspec.yaml

  • name: identificatore univoco del package (in minuscolo, senza spazi)

  • description: breve descrizione dell’app

  • version: <major>.<minor>.<patch>+<buildNumber> (es. 1.0.0+1)

  • Android (in android/app/src/main/AndroidManifest.xml o tramite Gradle)

  • applicationId: nel file android/app/build.gradle sotto defaultConfig

  • versionName e versionCode: gestiti automaticamente da Flutter in base a pubspec.yaml, ma possono essere sovrascritti in build.gradle

  • Permessi: dichiara solo quelli strettamente necessari (camera, geolocalizzazione, microfono, ecc.)

  • iOS (in ios/Runner/Info.plist)

  • CFBundleIdentifier: definito in Xcode → Runner → General → Identity

  • CFBundleShortVersionString e CFBundleVersion: sincronizzati con pubspec.yaml, ma modificabili in Xcode

  • Didascalie per permessi (Privacy – Camera Usage Description, Privacy – Location When In Use Usage Description, ecc.)

💡
Tip

Verifica sempre che nome, icona e permessi corrispondano alle linee guida di Play Store e App Store.


2. Gestione Assets

Obiettivo:

Organizzare, ottimizzare e configurare tutti gli asset dell’app (icone, splash screen, immagini e font) per garantire coerenza visiva e performance ottimali.


2.1 Icona e Splash Screen

  • Icona dell’app
  1. Aggiungi il pacchetto flutter_launcher_icons nel dev_dependencies di pubspec.yaml:
dev_dependencies: flutter_launcher_icons: ^0.9.2 flutter_icons: android: true ios: true image_path: "assets/icons/app_icon.png"
  1. Esegui:
flutter pub get flutter pub run flutter_launcher_icons:main
  • Splash screen nativo
  1. Aggiungi flutter_native_splash in dev_dependencies:
dev_dependencies: flutter_native_splash: ^2.2.16 flutter_native_splash: color: "#FFFFFF" image: "assets/images/splash.png" android: true ios: true
  1. Esegui:
flutter pub get flutter pub run flutter_native_splash:create
💡
Tip

Mantieni le immagini in alta risoluzione (almeno 1080×1080 px) per icone e splash, così da evitare aliasing su dispositivi con schermi ad alta densità.


2.2 Immagini e Font

  • Cartelle e struttura
  • Crea la struttura:
assets/ images/ fonts/
  • Dichiara gli asset in pubspec.yaml:
flutter: assets: - assets/images/ fonts: - family: MyFont fonts: - asset: assets/fonts/MyFont-Regular.ttf - asset: assets/fonts/MyFont-Bold.ttf
  • Ottimizzazione

  • Comprimi immagini con strumenti come TinyPNG

  • Usa formati moderni (WebP per Android, PNG per trasparenza)

  • Accesso in codice

Image.asset('assets/images/example.png'); Text( 'Titolo', style: TextStyle(fontFamily: 'MyFont'), );
💡
Tip

Considera l’uso di GIF o Lottie per animazioni leggere e di qualità.


3. Sicurezza e Privacy

Obiettivo:

Garantire protezione dei dati sensibili, rispetto della privacy degli utenti e conformità alle policy di store e normative.


3.1 Gestione dei Dati Sensibili

  • Archiviazione sicura
  • Utilizza flutter_secure_storage per salvare token, credenziali e dati critici.
final storage = FlutterSecureStorage(); await storage.write(key: 'token', value: token);
  • Chiavi API e segreti
  • Non hardcodare mai nel codice sorgente.
  • Carica tramite variabili d’ambiente o servizi di secret management (es. GitHub Actions Secrets, Firebase Remote Config).
💡
Tip

Usa file .env esclusi dal controllo versione (.gitignore) e librerie come flutter_dotenv per semplicità in sviluppo.


3.2 Permessi dell’App

  • Richiedi solo i permessi strettamente necessari:
  • Internet (per network)
  • Fotocamera/Storage (se necessario)
  • Configura le motivation captions:
  • Android (AndroidManifest.xml -> <uses-permission> e <application android:requestLegacyExternalStorage>)
  • iOS (Info.plist -> NSCameraUsageDescription, NSPhotoLibraryUsageDescription, ecc.)
💡
Tip

Mantieni le descrizioni concise e chiare: “L’app utilizza la fotocamera per scansionare codici QR”.


3.3 Privacy Policy e Conformità

  • Redigi una privacy policy che spieghi:
  • Tipologia di dati raccolti
  • Scopo del trattamento
  • Terze parti coinvolte (analytics, crash reporting)
  • Pubblica il documento su un dominio accessibile:
  • GitHub Pages, Notion, sito dedicato
  • Inserisci il link nel pannello di configurazione di Google Play Console e App Store Connect.
💡
Tip

Controlla le linee guida GDPR e CCPA se distribuisci in UE o California.


4. Testing & QA

Obiettivo:

Verificare la stabilità, la qualità e le performance dell’app su diversi dispositivi e scenari, garantendo un’esperienza utente fluida.


4.1 Test su Dispositivi Reali

  • Android:
  • Testa su almeno un dispositivo con Android 8.0+.
  • Controlla comportamenti su schermi di diverse dimensioni e DPI.
  • iOS:
  • Testa su un iPhone con iOS 13+ e se possibile un iPad.
  • Verifica conformità alle linee guida Apple (UI, performance).
💡
Tip

Esegui test su dispositivi entry-level e high-end per coprire casi di performance critiche.


4.2 Emulatori e Simulatori

  • Configura AVD in Android Studio con:
  • CPU: x86_64 e ARM
  • Risoluzioni comuni (720p, 1080p, 1440p)
  • Usa iOS Simulator per test rapidi su differenti versioni di iOS.
💡
Tip

Integra emulatori nel CI per test automatici su più configurazioni.


4.3 Performance e Profiling

  • Flutter DevTools:
  • Timeline: identifica frame skippati (>16ms).
  • Memory: monitora crescita della memoria nel tempo.
flutter pub global activate devtools flutter pub global run devtools
  • CPU Profiler:
  • Trova funzioni costose in build/repaint.

4.4 Test Automatizzati

  • Unit Test Isolano e verificano singole funzioni, classi o metodi della logica di business senza dipendenze esterne. Ideali per:

  • Validare algoritmi e calcoli (es. funzioni di formattazione, conversione)

  • Mockare servizi esterni (API, repository) con pacchetti come mockito o mocktail

  • Assicurare una copertura di codice elevata (obiettivo ≥ 80%)

  • Widget Test Eseguono test su widget individuali in un ambiente simulato, controllando:

  • Rendering corretto del layout e dei componenti UI

  • Interazioni dell’utente (tap, scroll, inserimento testo)

  • Stato interno del widget e aggiornamenti del widget tree

  • Utilizzo di pumpWidget, pumpAndSettle e Finder per selezionare widget

  • Integration Test Simulano flussi utente completi dall’avvio dell’app alla chiusura, su emulatori o dispositivi reali:

  • Automazione di tap, scroll e input di testo

  • Verifica di navigazione, autenticazione, salvataggio dati e chiamate di rete reali

  • Possibili approcci:

  • flutter_driver (legacy) con test_driver/app.dart

  • integration_test (consigliato) con test scritti accanto al codice (integration_test/app_test.dart)

Esempi di comandi

# Esegui Unit & Widget Test flutter test # Integration Test con flutter_driver flutter drive \ --target=test_driver/app.dart # Integration Test con package:integration_test flutter test integration_test
💡
Tip

Organizza test in cartelle test/unit, test/widget, test/integration per chiarezza.


5. Build Split (Android)

Obiettivo:

Generare pacchetti ottimizzati per ciascuna architettura, riducendo le dimensioni dell’app e migliorando il tempo di installazione.


5.1 Comando di Build Split

Esegui:

flutter build apk --split-per-abi

Questo comando produce più APK distinti in build/app/outputs/flutter-apk/:

  • app-armeabi-v7a-release.apk
  • app-arm64-v8a-release.apk
  • app-x86_64-release.apk

Ogni APK contiene soli i binari necessari all’architettura specificata.


5.2 Vantaggi

  • Dimensione ridotta: l’utente scarica solo il codice binario per il proprio device.
  • Installazione più veloce: pacchetto più leggero.
  • Navigazione semplificata: Play Store distribuisce automaticamente il file giusto.

5.3 Build App Bundle

Per il Play Store, Google consiglia l’App Bundle:

flutter build appbundle --target-platform android-arm,android-arm64,android-x64

Questo genera un file .aab che il Play Store usa per creare APK ottimizzati per gli utenti.

💡
Tip

L’App Bundle semplifica la gestione delle versioni e include il supporto di Play Feature Delivery e Play Asset Delivery.


5.4 Archiviazione e firma

  • Signing
  1. Configura key.properties e build.gradle con le tue chiavi.
  2. Esegui:
flutter build appbundle --build-name=1.0.0 --build-number=100
  • Verifica
jarsigner -verify -verbose -certs build/app/outputs/bundle/release/app-release.aab

6. Build Flavors in Flutter

Obiettivo: Creare varianti dell’app (dev, staging, prod) usando solo strumenti accessibili via Flutter.


6.1 Entrypoint & Dart-Define

Crea tre file Dart separati:

  • lib/main_dev.dart
  • lib/main_staging.dart
  • lib/main_prod.dart

Avvia il flavor via CLI:

flutter run --flavor dev -t lib/main_dev.dart --dart-define=API_URL=https://api-dev.example.com --dart-define=FIREBASE_PROJECT=myapp-dev --dart-define=SENTRY_DSN=https://dev-sentry.io/123 --dart-define=LOG_LEVEL=DEBUG

6.2 Configurazione EnvConfig

In ciascun entrypoint (main_dev.dart, etc.) importa e avvia l’app:

import 'package:flutter/material.dart'; import 'app.dart'; // il widget root della tua app void main() { runApp(MyApp()); }

Definisci la classe di configurazione:

class EnvConfig { static const apiUrl = String.fromEnvironment('API_URL'); static const firebaseProj = String.fromEnvironment('FIREBASE_PROJECT'); static const sentryDsn = String.fromEnvironment('SENTRY_DSN'); static const logLevel = String.fromEnvironment('LOG_LEVEL'); }

6.3 Esempio di utilizzo nel codice

Un semplice esempio di chiamata HTTP che usa EnvConfig:

import 'package:http/http.dart' as http; import 'env_config.dart'; class ApiService { Future<String> fetchData() async { final uri = Uri.parse('${EnvConfig.apiUrl}/items'); final resp = await http.get(uri); if (resp.statusCode == 200) { return resp.body; } else { throw Exception('Errore: ${resp.statusCode}'); } } }

Oppure mostra la configurazione sulla UI:

import 'package:flutter/material.dart'; import 'env_config.dart'; class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Settings (${EnvConfig.logLevel})')), body: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('API URL: ${EnvConfig.apiUrl}'), Text('Firebase: ${EnvConfig.firebaseProj}'), Text('Sentry DSN: ${EnvConfig.sentryDsn}'), ], ), ), ); } }

💡
Tip

Organizza assets in cartelle dedicate (assets/dev, assets/prod), mantieni naming coerente e integra i flavor nella pipeline CI/CD per build automatiche.


6.4 Vantaggi e Best Practice

  • Isolamento completo di endpoint, chiavi e asset
  • Rideploy sicuro su CI/CD con pipeline dedicate
  • Monitoring e Logging segmentati per ambiente
  • Feature Toggles per gestione graduale di nuove funzionalità

7. Build di Release

Obiettivo:

Costruire pacchetti finali pronti per la distribuzione su store ufficiali o canali alternativi, garantendo firma, versioning e conformità alle linee guida.


7.1 Android

  • APK di debug/testing
flutter build apk
  • App Bundle per Play Store
flutter build appbundle
  • Per specificare più architetture:
flutter build appbundle --target-platform android-arm,android-arm64,android-x64
  • Firma della release
  1. Crea key.properties con path del keystore, alias e password.
  2. Configura android/app/build.gradle per leggere key.properties.
  3. Esegui la build con versioning:
flutter build appbundle --build-name=1.0.0 --build-number=100
  • Verifica firma
jarsigner -verify -verbose -certs build/app/outputs/bundle/release/app-release.aab
💡
Tip

Controlla nella Play Console lo split per ABI e le dimensioni di download.


7.2 iOS

  • Prerequisiti

  • Mac con macOS e Xcode (versione ≥ 12).

  • Apple Developer account configurato in Xcode.

  • Build e Archiviazione

flutter build ios --release
  • Apre il workspace pronto per Archive.

  • In Xcode: Product → Archive → Upload to App Store Connect.

  • Firma e Provisioning

  • Seleziona il provisioning profile e certificate corretti.

  • Verifica che CFBundleIdentifier, CFBundleShortVersionString e CFBundleVersion siano corretti in Info.plist.

💡
Tip

Automatizza il caricamento su App Store Connect con xcrun altool o fastlane deliver.