Build Variant — cosa sono build type e product flavor in Android

Autore: IT Sectr Pubblicato: 2026-05-30 Tempo di lettura: 9 min

Un Build Variant nello sviluppo Android è una combinazione di un build type e un product flavor che determina come verrà compilato un APK o AAB: con quali parametri, risorse e codice. Ogni variante di build rappresenta una configurazione Gradle separata con il proprio applicationId, chiavi di firma e dipendenze incluse. Secondo Google Android Developers, 2025, una corretta configurazione dei Build Variants riduce il tempo di compilazione fino al 40% escludendo risorse non necessarie per ogni variante. Il sistema di varianti di build è il fondamento della gestione della configurazione nei progetti Android moderni.

Punti Chiave

  • Build Variant — combinazione di un Build Type e un Product Flavor.
  • Build Type definisce la modalità di compilazione: debug o release.
  • Product Flavor definisce la versione dell’app: free, paid, demo, enterprise.
  • Gradle genera automaticamente attività per ogni Build Variant, inclusi install e assemble.
  • Risorse e codice possono essere sovrascritti per ogni variante tramite i corrispondenti source set.

Cos’è un Build Variant?

Build Variant è il risultato della combinazione di un Build Type e un Product Flavor. Se nessun Product Flavor è definito nel progetto, il Build Variant corrisponde al Build Type. Gradle genera automaticamente l’insieme completo di varianti come prodotto cartesiano di tutti i FlavorDimensions, Product Flavors e Build Types. Ad esempio, per i flavor free/paid e i tipi debug/release, verranno create 4 varianti: freeDebug, freeRelease, paidDebug, paidRelease.

Ogni Build Variant riceve il proprio nome nel formato <Flavor><Type> con il flavor in maiuscolo. Gradle genera attività separate per questa variante: assembleFreeDebug, installFreeDebug, bundleFreeRelease. In Android Studio, il passaggio tra le varianti è disponibile tramite il pannello Build Variants (View → Tool Windows → Build Variants). La selezione di una variante influenza quale codice viene compilato, quali risorse vengono incluse e quale APK/AAB viene prodotto.

Il sistema Build Variants risolve tre compiti principali: separare le configurazioni per diversi ambienti (dev/staging/production), creare più versioni di un’app (free/paid) e testare A/B le compilazioni. Senza Build Variants, gli sviluppatori dovrebbero cambiare manualmente flag e configurazioni, portando a errori umani. Secondo uno studio di Gradle Inc., 2024, l’implementazione di Build Variants riduce gli errori di compilazione del 60% in progetti con tre o più ambienti di distribuzione.

Come Gradle genera le varianti

AGP (Android Gradle Plugin) calcola tutte le combinazioni nella fase di configurazione. Se un progetto ha due dimensioni rispettivamente con due e tre flavor, Gradle creerà 2 × 2 × 3 = 12 combinazioni, moltiplicate per il numero di Build Types (di solito 2). Ogni combinazione riceve un nome univoco e un insieme di attività. AGP aggiunge automaticamente un source set per ogni variante: src/freeDebug/, src/paidRelease/, nonché quelli generalizzati src/free/ e src/debug/. Priorità di lettura delle risorse: variant → flavor → type → main.

groovy
// Esempio: 4 Build Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// Totale: 2 × 2 × 2 = 8 varianti

android {
    flavorDimensions "version", "server"

    productFlavors {
        demo { dimension "version" }
        prod { dimension "version" }
        mock { dimension "server" }
        live { dimension "server" }
    }
}

Build Type e Product Flavor: Differenze

Build Type definisce come compilare l’applicazione — con o senza informazioni di debug, con o senza ottimizzazione, con quale firma. Product Flavor definisce cosa compilare — quale versione del prodotto. Build Type è un meccanismo di compilazione (debug, release, staging). Product Flavor è una variante di prodotto (free, paid, enterprise, demo). Entrambi i concetti sono ortogonali: qualsiasi Build Type può essere applicato a qualsiasi Product Flavor.

I Build Type predefiniti includono debug (debuggable=true, minification=false, signing=debug.keystore) e release (debuggable=false, minification=true, signing=production.keystore). Il Product Flavor predefinito è uno, senza nome (effettivamente il source set main). Gli sviluppatori possono aggiungere i propri Build Type (ad esempio, “staging” con debuggable=true e minification=true) e qualsiasi numero di Product Flavor. Un’altra differenza è che i Build Type non possono essere raggruppati in dimensioni, mentre i Product Flavor sì.

La differenza pratica principale: defaultConfig in build.gradle si applica a tutti i Variants ma può essere sovrascritto in productFlavors e buildTypes. Un BuildConfigField aggiunto a un buildType è visibile in tutti i flavor di quel tipo, mentre uno aggiunto a un productFlavor è visibile in tutti i tipi di quel flavor. Se un campo è definito in entrambi, buildType ha priorità (viene applicato per ultimo nella catena).

Tabella Comparativa

CaratteristicaBuild TypeProduct Flavor
ScopoCome compilareCosa compilare
Esempidebug, release, stagingfree, paid, demo, enterprise
Predefinitodebug + releaseuno (main)
Source Setsrc/debug/, src/release/src/free/, src/paid/
DimensioninoflavorDimensions
Ordine di applicazionedopo flavor, sovrascrivedopo defaultConfig
BuildConfigFieldsovrascrive flavorsovrascrive defaultConfig

Configurazione dei Build Variants in build.gradle

Priorità di Configurazione

La configurazione dei Build Variants viene effettuata nel blocco android del file build.gradle a livello di modulo. Prima vengono dichiarati i buildTypes con i loro parametri, poi flavorDimensions e productFlavors. Gradle crea automaticamente le varianti basandosi su queste dichiarazioni. Ogni variante eredita il defaultConfig del modulo, sovrascrivendo i campi specificati. L’ordine di dichiarazione influisce sulla priorità: i buildTypes vengono applicati dopo i productFlavors.

Per accedere a un Build Variant specifico negli script Gradle, utilizzare android.applicationVariants (per i moduli app) o android.libraryVariants (per i moduli libreria). Si tratta di una raccolta che può essere iterata per modificare la configurazione di ogni variante in fase di esecuzione della configurazione. Ad esempio, è possibile aggiungere programmaticamente buildConfigField per tutte le varianti contenenti la parola “demo”.

Android Gradle Plugin 8.x ha aggiunto il supporto per onVariants — un’API più pulita per configurare le varianti tramite lambda. La vecchia API (variantOutput, variantFilter) è stata contrassegnata come deprecata. Si consiglia di utilizzare onVariants insieme a onEach per i moduli libreria. Migrare da variantOutput a onVariants è un passo consigliato quando si aggiorna AGP da 7.x a 8.x.

groovy
android {
    buildTypes {
        debug {
            debuggable true
            minification false
            signingConfig signingConfigs.debug
        }
        release {
            debuggable false
            minification true
            proguardFiles "proguard-rules.pro"
            signingConfig signingConfigs.release
        }
        staging {
            debuggable true
            minification true
            versionNameSuffix "-staging"
        }
    }

    flavorDimensions "tier", "region"

    productFlavors {
        free { dimension "tier" }
        paid { dimension "tier" }
        us { dimension "region" }
        eu { dimension "region" }
    }
}

android.onVariants { variant ->
    if (variant.name.contains("Demo")) {
        variant.setEnabled(false)
    }
}

Source Set e Sovrascrittura delle Risorse

Ogni Build Variant riceve la propria gerarchia di source set — directory con codice sorgente, risorse e manifesto. Un source set si trova in src/<variantName>/ (ad esempio, src/freeDebug/) e può contenere java/, res/, AndroidManifest.xml, assets/. Se un file esiste nel source set della variante, sovrascrive il file con lo stesso nome dal source set principale (src/main/). Per le risorse, avviene un’unione anziché una sostituzione — il sistema unisce le risorse da tutti i source set attivi, dando priorità a quelli specifici della variante.

I source set per un Build Variant vengono costruiti in catena: src/main/src/flavor/src/type/src/flavorType/. Ad esempio, per paidRelease, viene applicato prima main, poi paid, poi release, poi paidRelease. Ogni source set successivo sovrascrive il precedente. Ciò significa che src/release/res/values/strings.xml sovrascriverà le stesse stringhe da src/paid/, ma src/paidRelease/res/ ha priorità ancora maggiore.

Utilizzare i source set per le varianti è il modo consigliato per personalizzare le risorse. Invece di controllare BuildConfig.FLAVOR nel codice e ramificare la logica, puoi semplicemente inserire file diversi in source set diversi. Ad esempio, le icone per le versioni free e paid vanno rispettivamente in src/free/res/ e src/paid/res/, e l’AndroidManifest con permessi diversi va in src/free/AndroidManifest.xml e src/paid/AndroidManifest.xml. Questo è più pulito, più veloce (le risorse vengono compilate, non controllate a runtime) e più sicuro (non puoi includere accidentalmente funzionalità a pagamento nella versione gratuita a causa di un bug nel codice).

Build Variant in Progetti Multimodulo

Nei progetti multimodulo, ogni modulo (libreria) può avere i propri Build Variants. AGP sincronizza automaticamente le varianti: se il modulo app compila paidRelease, tutte le librerie dipendenti vengono anch’esse compilate nelle loro varianti corrispondenti a paidRelease. Sorge un problema quando una libreria non ha product flavors ma il modulo app sì — allora la libreria viene compilata una volta (release o debug a seconda del tipo).

Per i moduli libreria, il Build Variant corrisponde per impostazione predefinita al Build Type del modulo app, poiché le librerie non hanno product flavors. Se una libreria deve adattarsi al flavor del modulo app, gli stessi flavorDimensions e productFlavors devono essere dichiarati nella libreria. AGP abbina i flavor per corrispondenza esatta del nome. Gradle consiglia di sincronizzare i flavor tramite la configurazione di build nel progetto root utilizzando subprojects o Convention Plugins.

A partire da AGP 8.1, le librerie possono pubblicare varianti multiple — pubblicare tutte le varianti della libreria in un repository maven contemporaneamente. Ciò risolve il problema quando il modulo app utilizza un flavor a pagamento ma la libreria è pubblicata solo per free. La pubblicazione di varianti multiple (MVP) consente al progetto dipendente di selezionare automaticamente la variante richiesta. Per abilitare MVP, aggiungi publishing { multipleVariants { ... } } al build.gradle della libreria.

Filtraggio e Disabilitazione delle Varianti

Filtraggio Dinamico tramite CI/CD

A volte è necessario disabilitare alcuni Build Variants — ad esempio, se la combinazione mockRelease non ha senso (il server mock non dovrebbe andare in produzione). Gradle fornisce variantFilter — un blocco DSL dove puoi controllare le proprietà di ogni variante e disabilitarla tramite setIgnore(true). VariantFilter viene applicato nella fase di configurazione, prima della creazione delle attività, quindi una variante disabilitata non genera attività assemble e install.

Il filtraggio è utile anche per accelerare le compilazioni. Se un progetto ha 8 varianti ma uno sviluppatore lavora su una sola, le restanti 7 varianti passano comunque attraverso la configurazione. Utilizzando variantFilter, le varianti disabilitate non creano attività, riducendo il tempo di configurazione del 30-50% per progetti con 6+ dimensioni di flavor. In CI/CD, puoi filtrare dinamicamente le varianti tramite parametri da riga di comando -PbuildOnly=paidRelease.

groovy
android {
    variantFilter { variant ->
        // Disabilitare mock per release e demo per production
        def names = variant.flavors*.name
        def isMock = names.contains("mock")
        def isDemo = names.contains("demo")
        def isRelease = variant.buildType.name == "release"

        if ((isMock && isRelease) || (isDemo && !isMock)) {
            variant.setIgnore(true)
        }
    }
}

// Filtraggio dinamico tramite parametri
if (project.hasProperty("buildOnly")) {
    def target = project.property("buildOnly")
    android.variantFilter { variant ->
        variant.setIgnore(variant.name != target)
    }
}

Domande Frequenti

Quanti Build Variants si possono creare?

Non c’è limite, ma Gradle crea il prodotto cartesiano di tutti i flavor e tipi. Se hai 3 dimensioni con 3 flavor ciascuna e 3 build types, ottieni 27 varianti. Troppe varianti rallentano la configurazione. Si consiglia di non avere più di 10–12 varianti in un modulo.

Perché servono i flavorDimensions?

I flavorDimensions raggruppano i Product Flavors in assi indipendenti. Ad esempio, la dimensione “tier” (free, paid) e la dimensione “region” (us, eu). Senza dimensioni, tutti i flavor appartengono a un unico asse e Gradle selezionerà solo un flavor da tutti (non puoi avere free+us e paid+eu come varianti separate).

Come sovrascrivere applicationId per una variante?

Nel blocco productFlavor o buildType, specifica applicationId. Ad esempio, per la versione gratuita: free { applicationId “com.example.app.free” }. Nel manifesto, usa ${applicationId} — Gradle sostituirà automaticamente il valore. Ciò consente di installare entrambe le varianti sullo stesso dispositivo.

Si possono usare i Build Variants in iOS?

In iOS, l’equivalente dei Build Variants è la combinazione di Scheme + Configuration. Gli Xcode Schemes vengono configurati tramite le configurazioni Debug/Release con parametri diversi. Per più versioni (free/paid), vengono utilizzate Build Configurations e Preprocessor Macros. Su Android, il concetto è più formalizzato e integrato in Gradle.

Il Build Variant influisce sulle dimensioni dell’APK?

Sì, ogni variante può avere dimensioni APK diverse. Le build debug includono informazioni di debug, SDK e risorse non supportate. Le build release con minification e resource shrinking producono le dimensioni minime. Anche il Product Flavor influisce sulle dimensioni: una versione gratuita senza librerie a pagamento sarà più piccola della versione a pagamento per la dimensione di quelle librerie.

Riepilogo

  • Build Variant — combinazione di un Build Type e un Product Flavor che definisce la configurazione di compilazione.
  • Build Type controlla la modalità di compilazione (debug/release/staging), mentre Product Flavor controlla la versione del prodotto (free/paid).
  • Source set permettono di sovrascrivere codice, risorse e manifesto per ogni variante di build.
  • VariantFilter disabilita combinazioni non necessarie, accelerando la configurazione di Gradle del 30–50%.
  • Progetti multimodulo richiedono la sincronizzazione dei flavor su tutti i moduli o la pubblicazione di varianti multiple.
  • BuildConfigField e source set sono due modi puliti per personalizzare il comportamento tra le varianti.
  • Raccomandazione: non creare più di 10–12 varianti in un progetto; raggruppa le dimensioni in modo significativo.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche