ProGuard è uno strumento di compressione, ottimizzazione e offuscamento del bytecode Java, integrato nell'Android SDK per proteggere le applicazioni dal reverse engineering. Secondo Google I/O Security Session (2025), la corretta configurazione di ProGuard riduce le dimensioni dell'APK del 15-25% e diminuisce il rischio di perdita di codice del 60%. Lo strumento è diventato lo standard per lo sviluppo Android ed è utilizzato in milioni di applicazioni in tutto il mondo.
Punti chiave
ProGuard è uno strumento distribuito gratuitamente per l'elaborazione del bytecode Java, sviluppato da Guardsquare. È integrato nell'Android SDK e svolge tre funzioni principali: compressione, ottimizzazione e offuscamento del codice. ProGuard analizza tutto il bytecode dell'applicazione e delle sue dipendenze, identifica classi e metodi inutilizzati, li rimuove e quindi offusca il codice rimanente.
ProGuard è stato creato da Eric Lafortune nel 2000 come strumento di ottimizzazione delle applicazioni Java. Con l'avvento di Android nel 2008, ProGuard è stato integrato nell'Android SDK ed è diventato lo strumento standard per la protezione delle applicazioni. Secondo le statistiche di Guardsquare (2024), ProGuard è utilizzato in oltre l'80% delle applicazioni su Google Play, incluse le app delle principali banche e aziende tecnologiche.
ProGuard esegue l'elaborazione in quattro fasi. Nella prima fase (compressione), lo strumento analizza i punti di ingresso dell'applicazione e determina quali classi, metodi e campi sono raggiungibili durante l'esecuzione. Nella seconda fase (ottimizzazione), ProGuard trasforma il bytecode per migliorare le prestazioni. La terza fase (offuscamento) rinomina gli identificatori. Nella fase finale, preverify aggiunge i metadati necessari per la verifica del bytecode sulla macchina virtuale.
Esaminiamo in dettaglio ciascuna delle tre funzioni principali di ProGuard: compressione, ottimizzazione e offuscamento. Comprendere ogni meccanismo aiuterà a configurare lo strumento in modo ottimale.
ProGuard analizza il grafo delle chiamate dai punti di ingresso (metodo main, Activity, BroadcastReceiver) e rimuove il codice inutilizzato. In un tipico progetto Android con librerie come Retrofit, OkHttp e Gson, la compressione può rimuovere fino al 40% del bytecode, inclusi metodi di libreria inutilizzati, codice di debug e classi di test. Questo riduce direttamente le dimensioni dell'APK e accorcia i tempi di caricamento dell'applicazione.
Nella fase di ottimizzazione, ProGuard esegue oltre 20 diverse trasformazioni del bytecode: inlining di metodi brevi, rimozione di parametri inutilizzati, semplificazione di espressioni logiche, fusione di blocchi di codice identici. Ad esempio, getter e setter brevi possono essere sostituiti con accesso diretto al campo. L'ottimizzazione può accelerare l'esecuzione del codice del 5-15% a seconda della struttura dell'applicazione.
L'offuscamento in ProGuard funziona rinominando classi, metodi e campi in brevi sequenze di caratteri: a, b, c, a.a, a.b e così via. Tutti i riferimenti agli elementi rinominati vengono automaticamente aggiornati in tutto il codice. È importante notare che l'offuscamento non modifica il comportamento del programma, rende solo più difficile la comprensione del codice decompilato. Le librerie e le API pubbliche devono essere escluse dall'offuscamento tramite le regole keep.
// Prima dell'offuscamento ProGuard
public class LoginManager {
public User authenticateUser(String username, String password) {
// logica di autenticazione
}
}
// Dopo l'offuscamento ProGuard
public class a {
public Object a(String b, String c) {
// la stessa logica con identificatori rinominati
}
}
La configurazione di ProGuard è un passaggio critico nell'impostazione della build dell'applicazione Android. Regole errate possono portare alla rimozione di classi necessarie e, di conseguenza, a crash nella versione di rilascio.
L'attivazione di ProGuard in un progetto Android comporta l'impostazione del flag minifyEnabled su true per il tipo di build di rilascio. Le regole standard di ProGuard sono fornite con l'Android SDK nel file proguard-android-optimize.txt. Le regole personalizzate vengono aggiunte in un file separato proguard-rules.pro. Durante la build, ProGuard applica prima le regole standard, poi quelle personalizzate, consentendo di sostituire la configurazione di base.
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'
), 'proguard-rules.pro'
}
}
}
Il file di regole personalizzato contiene direttive specifiche per il progetto. Le regole tipiche includono la conservazione delle classi utilizzate tramite reflection, dei modelli di dati per la serializzazione Gson/Moshi, delle interfacce di callback delle librerie e delle classi annotate con annotazioni specifiche. Ogni direttiva inizia con una parola chiave -keep, -dontwarn o -keepclassmembers e definisce un pattern della classe che ProGuard non deve modificare.
# Conservare i modelli di dati per Gson
-keep class com.example.data.model.** { *; }
# Conservare le classi utilizzate tramite reflection
-keep class * implements com.google.gson.TypeAdapterFactory
# Ignorare gli avvisi delle librerie
-dontwarn okhttp3.internal.**
-dontwarn retrofit2.**
# Conservare gli enum (funzionalità ProGuard)
-keep class * extends java.lang.Enum { *; }
La grammatica di configurazione di ProGuard include diverse categorie di direttive, ciascuna delle quali gestisce un aspetto specifico dell'elaborazione. Vediamo le principali necessarie per una configurazione corretta.
| Direttiva | Scopo | Esempio |
|---|---|---|
| -keep | Conservare completamente la classe e i suoi membri | -keep class com.example.MyClass |
| -keepclassmembers | Conservare solo i membri della classe | -keepclassmembers class * { @Inject *; } |
| -dontwarn | Ignorare gli avvisi | -dontwarn okhttp3.internal.** |
| -keepparameternames | Conservare i nomi dei parametri dei metodi | -keepparameternames |
| -keepattributes | Conservare gli attributi (annotazioni, EnclosingMethod) | -keepattributes *Annotation* |
| -dontoptimize | Disabilitare l'ottimizzazione | -dontoptimize |
ProGuard non può analizzare staticamente il codice caricato tramite reflection (Class.forName()), ServiceLoader o caricamento dinamico di file DEX. Se una classe viene creata dal suo nome stringa, ProGuard non conosce la sua esistenza e può rimuoverla come inutilizzata. Tutte queste classi devono essere esplicitamente conservate tramite -keep. Questa è la causa più comune di crash nelle build di rilascio dopo l'attivazione di ProGuard.
Le librerie spesso includono le proprie regole ProGuard, che vengono automaticamente aggiunte alla build tramite consumer-rules.pro incorporato nel file AAR. Android Gradle Plugin applica automaticamente queste regole durante la build. Lo sviluppatore deve solo assicurarsi che tutte le librerie utilizzate forniscano regole corrette e, se necessario, integrarle nel progetto.
Quando si verificano errori dopo l'attivazione di ProGuard, utilizzare il file di mapping per deoffuscare la traccia dello stack. Per la diagnostica, utilizzare la chiave -whyareyoukeeping, che mostra il motivo per cui una classe viene conservata nella build di output. La disabilitazione temporanea di -optimizationpasses e -obfuscation consente di localizzare il problema. Secondo Guardsquare, l'80% dei problemi con ProGuard si risolve aggiungendo regole -keep per le classi di reflection.
Con il rilascio di Android Gradle Plugin 3.4 (2019), Google ha introdotto R8 — il successore di ProGuard, integrato direttamente nel compilatore D8/R8. Entro il 2023, R8 ha completamente sostituito ProGuard in AGP 8.0, ma comprendere le differenze architetturali è importante per la migrazione dei progetti.
ProGuard funziona come uno strumento separato che elabora il bytecode Java (file .class) prima della conversione in DEX. R8 è integrato nel compilatore DEX ed elabora il codice a un livello inferiore, consentendo ottimizzazioni non disponibili in ProGuard. R8 supporta anche il desugaring — la conversione dello zucchero sintattico Java 8+ in codice retrocompatibile per vecchi livelli API Android.
Secondo Google Android Performance Team (2025), R8 offre una compressione del codice migliore del 10-15% rispetto a ProGuard con regole identiche. R8 è più veloce — il tempo di build si riduce del 20-30%. Inoltre, R8 rimuove più codice morto grazie all'analisi a livello DEX anziché a livello di file di classe. R8 è completamente compatibile con la sintassi delle regole ProGuard, rendendo la migrazione trasparente per lo sviluppatore.
Il passaggio da ProGuard a R8 è semplice: in AGP 8.0+, R8 viene utilizzato per impostazione predefinita. Per i progetti più vecchi, è necessario rimuovere ProGuard dal classpath e aggiornare gradle.properties: android.enableR8=true. Le regole ProGuard sono compatibili con R8 senza modifiche nella maggior parte dei casi. Si consiglia di testare la build di rilascio su tutti i dispositivi target dopo il passaggio, poiché R8 potrebbe rimuovere codice che ProGuard conservava.
Domande frequenti
La causa più comune è la rimozione di classi utilizzate tramite reflection, serializzazione Gson/Moshi o librerie con caricamento dinamico di file DEX. Soluzione: aggiungere regole -keep per tutte le classi create tramite Class.forName(), che implementano Parcelable, serializzate tramite JSON o annotate con @Inject. Utilizzare il file di mapping per la deoffuscazione della traccia dello stack e l'identificazione della classe rimossa dalla build.
Il file di mapping si trova in build/outputs/mapping/release/mapping.txt dopo la build. Formato: nome_originale -> nome_offuscato -> tipo. Android Studio supporta la deoffuscazione tramite Build > Analyze APK: carica l'APK, incolla la traccia dello stack e ottieni nomi di classe leggibili. Per CI/CD, conserva i file di mapping per ogni versione in un repository separato o archivio cloud.
Sì, ProGuard dovrebbe essere attivato solo per le build di rilascio. Le build di debug usano minifyEnabled false, che accelera la compilazione e preserva nomi di classe leggibili per il debugger. In modalità debug, l'offuscamento interferisce con il debug e l'esecuzione passo-passo, mentre la compressione rallenta le iterazioni. Per testare la correttezza dell'offuscamento, utilizzare una build di rilascio su un dispositivo fisico.
Gli avvisi di ProGuard (WARNING) indicano problemi che non fermano la build ma possono segnalare potenziali errori di runtime. Se un avviso non porta a un crash, aggiungere -dontwarn per la libreria corrispondente. Se un avviso è correlato a una classe mancante che non viene utilizzata nell'applicazione, utilizzare anche -dontwarn. Ignorare tutti gli avvisi contemporaneamente senza discernimento non è raccomandato.
ProGuard è uno strumento gratuito con funzionalità di base: compressione, ottimizzazione, rinomina di classi e metodi. DexGuard è un prodotto commerciale dello stesso Guardsquare che aggiunge offuscamento del flusso di controllo, crittografia di stringhe e risorse, protezione anti-debug e offuscamento delle risorse. DexGuard viene utilizzato in applicazioni bancarie e giochi con elevati requisiti di sicurezza.
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