Build Type nello sviluppo Android è una configurazione di Gradle che determina come l'applicazione viene compilata: con o senza debug, con o senza ottimizzazione del codice e con quale certificato di firma. Android Gradle Plugin fornisce due Build Type standard — debug e release, e lo sviluppatore può aggiungere tipi personalizzati, come staging o benchmark. Secondo Google Android Developers, 2025, una corretta configurazione di Build Type riduce la dimensione dell'APK fino al 60% grazie a minification e resource shrinking. Ogni Build Type viene combinato con Product Flavors per formare un Build Variant.
Punti chiave
Build Type è un elemento della configurazione di Gradle nei progetti Android che descrive i parametri di compilazione e impacchettamento dell'applicazione. Ogni Build Type è un insieme nominato di opzioni: debuggable (abilitare il debug), minificationEnabled (abilitare la compressione del codice), shrinkResources (abilitare la compressione delle risorse), proguardFiles (file di regole ProGuard), signingConfig (certificato di firma) e altri. I Build Type vengono dichiarati nel blocco android.buildTypes del file build.gradle del modulo app.
Lo scopo principale di Build Type è separare il flusso di sviluppo (build rapido, log dettagliati, debug) dal rilascio di produzione (codice ottimizzato, dimensione minima, sicurezza). Il build debug deve compilare in secondi e fornire il massimo delle informazioni allo sviluppatore. Il build release deve essere il più veloce e compatto possibile per gli utenti. Build Type è un'impostazione di infrastruttura, non correlata alla funzionalità dell'applicazione.
Android Gradle Plugin crea automaticamente un source set per ogni Build Type — la directory src/<buildType>/ (ad esempio, src/debug/, src/release/). Le risorse, il codice e i file del manifest inseriti in questo source set si applicano solo a quel tipo di build. Ad esempio, in src/debug/ può essere inserito un AndroidManifest.xml con autorizzazione all'installazione da ADB, mentre in src/release/ senza. Il source set di Build Type ha priorità rispetto al source set di Product Flavor.
La differenza chiave: Build Type risponde alla domanda "come compilare?", mentre Product Flavor risponde a "cosa compilare?". Build Type può essere debug, release, staging. Product Flavor può essere free, paid, enterprise. Build Type non modifica la funzionalità dell'applicazione (non aggiunge né rimuove schermate), Product Flavor lo fa. Build Type può disabilitare il debugger e abilitare l'offuscamento, Product Flavor può modificare applicationId e risorse. Entrambi lavorano insieme: ogni Build Type viene combinato con ogni Product Flavor per formare un Build Variant.
Debug è il Build Type creato per impostazione predefinita da AGP. Ha debuggable=true, che consente di collegare il debugger, visualizzare i log Log.d e utilizzare il profiler di Android Studio. La minification è disattivata, quindi il build è rapido. In un build debug, applicationId riceve il suffisso ".debug" (se non sovrascritto), consentendo di installare la versione debug insieme alla versione release sullo stesso dispositivo. Il build debug viene firmato con un certificato da debug.keystore, creato automaticamente da Android SDK.
Release è il Build Type per pubblicare l'applicazione. debuggable=false, minificationEnabled=true (predefinito), shrinkResources=true. Lo sviluppatore deve specificare un signingConfig con un certificato di produzione — altrimenti il build non sarà considerato un build release. Il build release utilizza ProGuard o R8 per offuscamento, ottimizzazione e compressione del codice. Android Studio non può collegare il debugger a un build release (se debuggable=false). Tutte le chiamate Log.d e Log.v vengono rimosse dal codice durante la minification se sono configurate le appropriate regole ProGuard.
Importante: i build debug non testano il comportamento release. La minification può modificare il comportamento del codice — reflection, serializzazione, Gson/SQLite e altre librerie richiedono spesso regole ProGuard. Pertanto, compila e testa sempre un build release prima della pubblicazione. Google Play Console e Firebase Test Lab consentono di caricare build release per test automatici su dispositivi reali prima della pubblicazione.
android {
buildTypes {
debug {
debuggable true
minification false
signingConfig signingConfigs.debug
versionNameSuffix "-debug"
}
release {
debuggable false
minification true
shrinkResources true
proguardFiles "proguard-rules.pro"
signingConfig signingConfigs.release
ndk { abiFilters "arm64-v8a", "x86_64" }
}
}
}
Oltre a debug e release, è possibile creare Build Type personalizzati — ad esempio staging (ambiente intermedio) o benchmark (per test delle prestazioni). Un Build Type personalizzato viene dichiarato nel blocco buildTypes proprio come debug e release. Il nome può essere qualsiasi, ma si consiglia di utilizzare nomi semanticamente chiari in inglese. Per staging, di solito si imposta debuggable=true (per diagnosticare problemi nell'ambiente staging) e minification=true (per testare l'offuscamento prima della produzione).
Un Build Type personalizzato ottiene automaticamente un source set corrispondente (src/staging/) e genera attività come assembleStaging. AGP non impone limiti sul numero di tipi personalizzati, ma ogni nuovo tipo moltiplica il numero di Build Variant. Il limite pratico è di 4-5 Build Type: debug, staging, benchmark, release e possibilmente debugMinified (debug con minification abilitata per testare le regole ProGuard).
Per un Build Type personalizzato, puoi ereditare debuggable da debug usando initWith. La parola chiave initWith copia tutti i parametri del Build Type specificato, dopodiché possono essere sovrascritti. Ciò è comodo per creare staging basato su debug: initWith debug + abilitare ulteriormente minification. Senza initWith, dovresti elencare manualmente tutti i parametri del tipo base.
android {
buildTypes {
staging {
initWith debug
minification true
shrinkResources true
proguardFiles "staging-proguard-rules.pro"
versionNameSuffix "-staging"
}
benchmark {
initWith release
signingConfig signingConfigs.debug
matchingFallbacks = ["release"]
}
}
}
// matchingFallbacks — per librerie che non hanno un tipo benchmark
// se la libreria ha solo release — AGP lo usa
SigningConfig determina quale certificato viene utilizzato per firmare l'APK o l'AAB. Android richiede che tutte le applicazioni installabili siano firmate — senza ciò, il sistema non consentirà l'installazione. Per i build debug, AGP utilizza debug.keystore — un certificato preinstallato con una password nota generato da Android SDK Tools. Per i build release, devi creare il tuo certificato tramite Android Studio (Build → Generate Signed Bundle/APK) o tramite la riga di comando keytool.
La conservazione delle chiavi di firma è un aspetto critico della sicurezza. Si raccomanda di non conservare le chiavi release nel repository del codice sorgente. Invece, utilizza un file keystore.properties (aggiunto a .gitignore), variabili d'ambiente CI/CD o l'archivio crittografato di Android Studio. In CI/CD (GitHub Actions, GitLab CI), le chiavi di firma sono conservate in secrets e passate a build.gradle tramite proprietà di sistema. Esempio: storePassword = System.getenv("KEYSTORE_PASSWORD").
Ogni Build Type può fare riferimento al proprio signingConfig. Per release — un certificato di produzione, per debug — debug.keystore, per staging — un certificato staging separato. La configurazione di firma influisce direttamente sulla possibilità di installare l'applicazione: se firmi debug con debug.keystore e staging con una chiave di produzione, staging non può essere installato sopra la versione debug a causa della mancata corrispondenza delle firme. Anche applicationId deve differire — utilizza applicationIdSuffix per questo.
android {
signingConfigs {
debug {
storeFile file("debug.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
release {
storeFile file("release-key.jks")
storePassword System.getenv("KEYSTORE_PASS")
keyAlias "my-key"
keyPassword System.getenv("KEY_PASS")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
Minification è il processo di rimozione del codice inutilizzato e di rinomina di classi, metodi e campi in nomi brevi. AGP esegue la minification con ProGuard (legacy) o R8 (consigliato, integrato in AGP a partire dalla versione 3.4). R8 esegue quattro operazioni: shrinking (rimozione delle classi inutilizzate), optimisation (semplificazione del codice), obfuscation (rinomina) e preverify (aggiunta di informazioni di compatibilità). Il risultato è un APK più piccolo e più difficile da decompilare.
Le regole di minification sono definite in file di regole ProGuard — file di testo con sintassi come -keep, -dontwarn, -keepclassmembers. Senza regole, R8 rimuoverà o rinominerà le classi utilizzate tramite reflection (Gson, Retrofit, Room, serializzazione Kotlin). Il modello di progetto Android Studio crea un file proguard-rules.pro in cui vengono aggiunte regole per librerie specifiche. Le librerie possono anche contenere regole integrate — vengono incluse automaticamente da jar/aar.
Shrink resources (shrinkResources=true) rimuove le risorse inutilizzate dall'APK. R8 prima determina quali risorse non sono utilizzate nel codice (verifica R.java e i riferimenti del manifest), quindi le rimuove dal build finale. Per le risorse utilizzate tramite getIdentifier() o da librerie di terze parti, è necessario aggiungere tools:keep="@layout/my_layout" nelle risorse. Combinato con la minification, il resource shrinking può ridurre la dimensione dell'APK del 40-60%.
# proguard-rules.pro — regole obbligatorie
# Gson: mantenere le classi per la serializzazione
-keepclassmembers class com.example.** {
<fields>;
}
# Retrofit: mantenere le interfacce API
-keep,allowobfuscation interface com.example.api.*
# Room: mantenere DAO ed Entity
-keep class * extends androidx.room.RoomDatabase
-keep @interface androidx.room.** { *; }
# Kotlin Coroutines: impedire la rimozione di Continuation
-keepnames class kotlinx.coroutines.internal.*
# OkHttp: preservare il service loader
-keep class okhttp3.** { *; }
BuildConfig è una classe Java/Kotlin generata automaticamente che contiene costanti definite in defaultConfig, productFlavors e buildTypes. Tramite buildConfigField possono essere aggiunti campi personalizzati: buildConfigField "String", "API_URL", '"https://api.example.com"'. Un BuildConfigField dichiarato in buildType è disponibile in tutte le varianti di quel tipo. I valori in buildType sovrascrivono i valori di productFlavor, che a loro volta sovrascrivono defaultConfig.
Per i build debug, è comodo impostare API_URL su localhost o un server staging, e per release — sulla produzione. Anche BuildConfig.FLAVOR e BuildConfig.BUILD_TYPE sono generati automaticamente e contengono il nome del flavor e del build type correnti. Nel codice puoi usare: if (BuildConfig.DEBUG) { /* log */ } — la costante DEBUG è vera solo per il build type debug. BuildConfig.DEBUG è un campo standard che AGP aggiunge a ogni BuildConfig.
Le risorse per Build Type sono definite tramite il source set src/<buildType>/res/. Ad esempio, src/debug/res/values/strings.xml può contenere la stringa "Server: Dev", mentre src/release/res/ può contenere "Server: Prod". Anche le risorse del manifest vengono sovrascritte tramite il source set: src/debug/AndroidManifest.xml può includere <uses-permission android:name="android.permission.INTERNET" /> solo per i build debug. Ciò è più pulito che verificare BuildConfig nel codice e funziona anche per attributi che non possono essere impostati programmaticamente (come networkSecurityConfig).
// src/debug/kotlin/.../DebugConfig.kt
object DebugConfig {
val apiUrl = "http://localhost:8080/api"
val enableLogging = true
val enableCrashReporting = false
}
// src/release/kotlin/.../ReleaseConfig.kt
object ReleaseConfig {
val apiUrl = "https://api.production.com/v2"
val enableLogging = false
val enableCrashReporting = true
}
// Utilizzo: la classe principale carica Config tramite reflection
fun getConfig(): AppConfig = when (BuildConfig.BUILD_TYPE) {
"debug" -> DebugConfig
else -> ReleaseConfig
}
Domande frequenti
Sì, crea un Build Type personalizzato come debugMinified con initWith debug e attiva la minification: debugMinified { initWith debug; minification true }. Ciò è utile per testare le regole ProGuard senza compilare una versione release completa.
Esegui apksigner da Android SDK: apksigner verify --print-certs app-release.apk. Se il certificato corrisponde a quello caricato in Google Play Console, la firma è corretta. Puoi anche verificare con jarsigner per i formati più vecchi.
matchingFallbacks specifica quale Build Type di una libreria utilizzare se questa non ha il tipo richiesto. Ad esempio, se l'app ha un tipo "staging" ma la libreria ha solo "release", AGP usa release per la libreria. Viene specificato come elenco: matchingFallbacks = ["release", "debug"].
Nelle regole ProGuard, usa -keep per le classi della libreria. Esempio: -keep class com.some.library.** { *; }. Per disabilitare completamente la minification per tutte le librerie, specifica -dontobfuscate e -dontoptimize in proguard-rules.pro.
Build Type di per sé non modifica minSdk né targetSdk. Tuttavia, puoi impostare minSdk per un Build Type specifico: debug { minSdk 21 }. Ciò è utile per i build debug — puoi supportare solo API 21+ per velocizzare la compilazione, mentre i build release usano minSdk 26.
Riepilogo
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.
Leggi anche