ProGuard e R8 são ferramentas de ofuscação, minificação e otimização para aplicativos Android. O ProGuard, criado em 2002, foi por muito tempo o padrão de facto para proteção de código Java. O R8 é seu sucessor, desenvolvido pelo Google e integrado ao Android Gradle Plugin a partir do AGP 3.4. Ambas as ferramentas reduzem o tamanho do APK, removem código morto e dificultam a engenharia reversa. De acordo com Android Developers, o R8 executa compilações 2–3 vezes mais rápido que o ProGuard com qualidade de ofuscação comparável.
Pontos Principais
ProGuard é uma ferramenta de código aberto (Apache 2.0) para ofuscação, minificação, otimização e pré-verificação de bytecode Java. Foi desenvolvido por Eric Lafarge em 2002 como parte do projeto SourceForge. O ProGuard recebe classes Java compiladas (.class) ou arquivos JAR como entrada e produz classes processadas do mesmo formato, mas com tamanho menor e elementos renomeados.
Por muito tempo, o ProGuard foi o único padrão para proteger aplicativos Android contra engenharia reversa. O Google recomendou oficialmente seu uso no Android SDK e forneceu uma configuração padrão no arquivo proguard-android-optimize.txt dentro das ferramentas do SDK. O ProGuard funcionava como uma ferramenta separada, executada após a compilação do código Java em bytecode e antes da empacotamento em DEX.
O ProGuard consiste em quatro fases sequenciais: shrink (remoção de classes não utilizadas), optimize (otimização de bytecode — inlining, remoção de código morto), obfuscate (renomeação de classes, métodos e campos para nomes curtos), preverify (verificação de compatibilidade com JVM). Cada fase é controlada por regras separadas dos arquivos de configuração.
Durante o estágio de ofuscação, o ProGuard gera um arquivo de mapeamento (mapping.txt) que mapeia os nomes originais para os ofuscados. Este arquivo é crítico para decodificar logs de falhas de builds de lançamento usando o utilitário retrace. Sem um arquivo de mapeamento, um stack trace se torna um conjunto de letras a(), b(), c() sem possibilidade de restaurar o contexto original.
| Fase do ProGuard | Propósito | Resultado |
|---|---|---|
| Shrink | Análise do grafo de chamadas e remoção de código morto | Menos classes no APK |
| Optimize | Inlining de métodos, remoção de parâmetros não utilizados | Execução de código mais rápida |
| Obfuscate | Renomeação de classes, campos e métodos | Proteção contra engenharia reversa |
| Preverify | Adição de atributos StackMap para JVM | Compatibilidade com Java 6+ |
R8 é uma ferramenta de ofuscação e minificação de próxima geração do Google, apresentada pela primeira vez no Android Studio 3.3 (novembro de 2018) e tornando-se padrão no AGP 3.4 (agosto de 2019). Diferentemente do ProGuard, o R8 faz parte do compilador D8/R8 que converte bytecode Java em formato DEX. O R8 realiza todas as fases — ofuscação, minificação e otimização — em uma única passada, sem passar arquivos intermediários entre ferramentas.
O Google desenvolveu o R8 com dois objetivos: acelerar as compilações (o ProGuard funcionava como ferramenta externa) e fornecer integração perfeita com a pilha moderna do Android (Desugar, Core Library Desugaring, D8). O R8 é escrito em Kotlin e Java e faz parte do repositório R8/Desugar no AOSP (Android Open Source Project).
Uma vantagem importante do R8 é a compatibilidade total com versões anteriores das regras do ProGuard. Os arquivos .pro existentes funcionam sem alterações. O R8 até suporta diretivas específicas do ProGuard, incluindo -whyareyoukeeping, -printconfiguration e -printmapping. Isso significa que a transição do ProGuard para o R8 é transparente: basta atualizar o AGP.
// build.gradle.kts — ativação do R8 via minifyEnabled
android {
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
// Configuração básica do Android SDK
getDefaultProguardFile("proguard-android-optimize.txt"),
// Regras personalizadas do projeto
"proguard-rules.pro"
)
}
}
}O código mostra uma configuração padrão de build de lançamento. A flag isMinifyEnabled = true ativa o R8 para ofuscação e otimização. isShrinkResources = true remove adicionalmente recursos não utilizados. getDefaultProguardFile carrega as regras padrão do SDK, enquanto o proguard-rules.pro contém configurações específicas do projeto.
Ofuscação é o processo de transformar o código fonte em uma forma difícil de analisar por humanos, mas que mantém toda a funcionalidade. No contexto do Android, ofuscação significa renomear classes, métodos e campos para nomes curtos e sem significado: com.example.app.auth.LoginManager torna-se a.a.a, o método authenticateUser torna-se a, o campo userToken torna-se b.
Os arquivos APK do Android são arquivos que podem ser abertos com qualquer arquivador (ZIP, 7z, WinRAR). Sem ofuscação, um invasor obtém um mapa completo do aplicativo: nomes de pacotes, classes, métodos e campos. Ferramentas como jadx ou Bytecode Viewer podem restaurar código Java quase original de arquivos DEX em segundos. A ofuscação não torna o código invulnerável, mas eleva significativamente a barreira de entrada: em vez de nomes significativos, o leitor vê a(), b(), c().
Objetivos típicos da ofuscação: proteger a lógica comercial (algoritmos, fórmulas de cálculo), dificultar o roubo de chaves de API e tokens, prevenir a substituição de classes via reflection e evitar modificação e repacotamento de APK (ataque de reempacotamento). Na prática, 70% das tarefas são resolvidas apenas com a renomeação — por isso o ProGuard/R8 é usado.
Abaixo está um arquivo típico proguard-rules.pro para um projeto Android com Retrofit, Gson e Parcelable. As regras -keep preservam classes e métodos necessários para a operação das bibliotecas através de reflection. Sem essas regras, o R8 removerá ou renomeará classes que a biblioteca acessa por nome de string.
# =====================
# Retrofit — preservação de interfaces
# =====================
-keep,allowobfuscation,allowshrinking interface retrofit2.** { *; }
-keepattributes Signature, Exceptions
# =====================
# Gson — serialização JSON
# =====================
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep class *.serialization.** {
<fields>;
}
# =====================
# Parcelable — Creator
# =====================
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
# =====================
# Logging — remoção de logs da versão de lançamento
# =====================
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(String, int);
public static int v(...);
public static int d(...);
public static int i(...);
public static int w(...);
public static int e(...);
}
# =====================
# Classes de dados Kotlin — preservação de construtores
# =====================
-keepclassmembers class * {
@kotlin.Metadata <fields>;
}
# =====================
# Activity — ponto de entrada
# =====================
-keep class * extends android.app.Activity {
@android.annotation.SuppressLint <methods>;
}Cada diretiva em um arquivo .pro resolve uma tarefa específica. -keep impede que a classe inteira seja removida ou renomeada. -keepclassmembers protege apenas os membros da classe (campos e métodos), mas permite que a classe em si seja removida se não for usada. -assumenosideeffects informa ao R8 que uma chamada de método não tem efeitos colaterais e pode ser removida com segurança. A diretiva -keepattributes preserva metadados no bytecode — anotações, assinaturas, exceções.
A regra -keep,allowobfuscation,allowshrinking para Retrofit permite que o R8 renomeie as interfaces, mas não as remova. Isso é necessário porque o Retrofit acessa interfaces através de proxies dinâmicos (java.lang.reflect.Proxy), e a remoção resultaria em ClassNotFoundException em tempo de execução. Da mesma forma, o Gson usa reflection para acessar campos anotados com @SerializedName — sem -keepclassmembers, os campos serão removidos como não utilizados.
Minificação (shrinking) é o processo de remover código e recursos não utilizados do build final. O ProGuard e o R8 analisam o grafo de chamadas a partir dos pontos de entrada (Activity, Service, BroadcastReceiver) e removem classes e métodos que não podem ser alcançados através da cadeia de chamadas. ShrinkResources é um estágio adicional que remove recursos não utilizados de res/ (layout, drawable, string, color).
A minificação proporciona o maior benefício em projetos grandes com bibliotecas. Um cenário típico: um projeto usa 10% do código de uma biblioteca conectada (por exemplo, Google Play Services). Sem minificação, todo o código da biblioteca vai para o APK. Com minificação, o R8 remove 70–90% do código da biblioteca, deixando apenas as classes e métodos realmente usados. Isso impacta diretamente o tamanho do APK, o tempo de carregamento e o consumo de memória.
O mecanismo ShrinkResources funciona em conjunto com a minificação de código. Depois que o R8 determina quais classes são usadas, a redução de recursos analisa as referências a recursos do código: R.layout.main, R.drawable.icon, getString(R.string.title). Todos os recursos sem referência direta ou indireta são removidos do APK ou AAB final. Isso é feito usando o arquivo de recursos resources.arsc e as pastas res/.
Uma nuance importante: os recursos podem ser acessados via getIdentifier() ou Resources.getResourceName() por nome de string, contornando a classe R. Nesses casos, o R8 não vê um link direto e pode remover um recurso que está realmente sendo usado. Para proteger tais recursos, existe a diretiva -keep class **.R$* { *; } — ela preserva todos os identificadores da classe R.
<!-- Exemplo: recurso usado apenas através de getIdentifier() -->
<string name="dynamic_title_welcome">Bem-vindo</string>
<string name="dynamic_title_share">Compartilhar</string>
<!-- Código Kotlin que acessa por string -->
<!-- val title = getString(resources.getIdentifier( -->
<!-- \"dynamic_title_${type}\", \"string\", packageName)) -->Neste caso, o R8 não vê uma referência estática a dynamic_title_welcome na classe R porque o acesso é através de getIdentifier com um nome dinâmico. Para preservar tais recursos, adicione a diretiva -keepclassmembers class **.R$string { *; } ao proguard-rules.pro — ela impede a remoção de qualquer campo de todas as classes R$string.
| Diretiva | Propósito | Exemplo |
|---|---|---|
| -keep | Preserva a classe e todos os seus membros | -keep class com.example.api.** { *; } |
| -keepclassmembers | Preserva apenas os membros da classe | -keepclassmembers class * { @SerializedName <fields>; } |
| -keepattributes | Preserva metadados do bytecode | -keepattributes *Annotation*, Signature |
| -assumenosideeffects | Remove chamadas sem efeitos colaterais | -assumenosideeffects class Log { d(...); } |
| -dontwarn | Suprime avisos | -dontwarn com.example.legacy.** |
Apesar de o R8 ser o sucessor do ProGuard, existem diferenças fundamentais entre as ferramentas em arquitetura, desempenho e comportamento. O Google encerrou oficialmente o suporte ao ProGuard no Android Gradle Plugin a partir do AGP 7.0, mas o ProGuard continua sendo usado em projetos que exigem comportamento de otimização específico não disponível no R8.
| Característica | ProGuard | R8 |
|---|---|---|
| Desenvolvedor | GuardSquare (Eric Lafarge) | |
| Ano de lançamento | 2002 | 2018 (estável em 2019) |
| Arquitetura | 4 fases separadas (shrink → optimize → obfuscate → preverify) | Única passada: shrink + optimize + obfuscate simultaneamente |
| Integração no AGP | Ferramenta externa, executada após javac | Integrada ao compilador D8 DEX |
| Velocidade de compilação | 2–3 vezes mais lento | Mais rápido devido à passada única e integração nativa |
| Suporte a Kotlin | Limitado (problemas com inline, lambdas, coroutines) | Completo: coroutines, funções inline, data class |
| Arquivo de mapeamento | mapping.txt (compatível com retrace) | mapping.txt (mesmo formato) |
| Personalização de otimização | 60+ opções -optimizationpasses, -optimizations | Limitada: a maioria das otimizações ativadas por padrão |
| Status de suporte | Substituído pelo R8 (AGP 7.0+ não usa) | Desenvolvimento ativo, parte do AOSP |
O R8 é mais agressivo que o ProGuard na remoção de código que considera morto. Isso leva a situações em que o build de depuração funciona, mas o build de lançamento falha com ClassNotFoundException ou NoSuchMethodException. Casos típicos: bibliotecas que usam reflection por nome de classe (Gson, Moshi, Retrofit, Room, Dagger); chamadas ServiceLoader ou java.util.ServiceLoader; proxies dinâmicos (java.lang.reflect.Proxy); métodos nativos (JNI). A solução é adicionar -keep para todas as classes que são chamadas através de reflection.
# Problemas típicos de reflection — R8 não vê o link estático
# Room — preservação de DAO e migrações
-keep class * extends androidx.room.RoomDatabase { *; }
-keep class *.DatabaseMigrations { *; }
# Dagger / Hilt — preservação de componentes
-keep class * extends dagger.hilt.android.components.** { *; }
# JNI — não renomear métodos nativos
-keepclasseswithmembernames class * {
native <methods>;
}
# Data Binding — preservação de classes Binding
-keep class *.databinding.** { *; }Se após adicionar regras o build ainda falhar, use a flag -printconfiguration full-config.txt no proguard-rules.pro. O R8 gerará um arquivo de configuração completo mostrando quais regras são aplicadas e quais classes são preservadas. Também é útil a diretiva -whyareyoukeeping class com.example.MyClass — ela exibe o motivo pelo qual o R8 decidiu preservar a classe em questão.
A configuração adequada das regras do ProGuard é a chave para uma ofuscação estável sem erros em tempo de execução. Abaixo está um processo de configuração passo a passo para um novo projeto ou para um projeto onde a ofuscação causa erros.
Comece incluindo o arquivo padrão do Android SDK — proguard-android-optimize.txt. Ele contém regras para componentes básicos do Android: Activity, Service, BroadcastReceiver, ContentProvider, View, Fragment. Este arquivo está localizado na pasta do SDK: $ANDROID_HOME/tools/proguard/proguard-android-optimize.txt. Se você usa AGP, o getDefaultProguardFile o carregará automaticamente.
Cada biblioteca popular tem regras ProGuard recomendadas. Retrofit, OkHttp, Glide, Fresco, Coil, Room, Dagger/Hilt, Kotlin Coroutines — todas exigem regras -keep específicas. Normalmente, as regras estão incluídas na biblioteca AAR e são vinculadas automaticamente através de regras de consumidor. Verifique se a biblioteca fornece um arquivo proguard.txt dentro do AAR — isso indica que as regras já foram consideradas.
Antes de publicar, certifique-se de testar o build de lançamento em um dispositivo real ou emulador. Os problemas de ofuscação só se manifestam em tempo de execução. Verifique: autenticação (login/registro), carregamento de dados da rede, navegação entre telas, câmera e galeria, notificações push, Deeplinks, WebView. Cada falha no build de lançamento precisa ser decodificada usando retrace com o arquivo de mapeamento, e as regras -keep faltantes devem ser adicionadas.
O arquivo de mapeamento é gerado em build/outputs/mapping/release/mapping.txt. Este arquivo deve ser preservado: sem ele, é impossível decodificar logs de falhas do Google Play Console. Inclua o mapping.txt no seu sistema de controle de versão ou faça upload dele como artefato de CI. O Google Play Console aceita o arquivo de mapeamento automaticamente ao fazer upload de um AAB com uploading mapping.txt ativado.
Abaixo está um fluxo de trabalho completo de configuração de ofuscação no arquivo proguard-rules.pro com comentários para cada grupo de regras.
# ===========================================
# proguard-rules.pro — exemplo completo
# ===========================================
# --- Configurações gerais ---
-keepattributes *Annotation*, Signature, Exceptions, InnerClasses, EnclosingMethod
-dontpreverify
# --- Componentes Android ---
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.Fragment
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends android.view.View
# --- OkHttp / Retrofit ---
-dontwarn okhttp3.**
-dontwarn okio.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions
# --- Gson / Moshi ---
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep class com.google.gson.** { *; }
# --- Firebase ---
-keep class com.google.firebase.** { *; }
-keep class com.google.android.gms.** { *; }
# --- Kotlin Coroutines ---
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
# --- Serialização ---
-keepclassmembers class * implements java.io.Serializable {
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# --- Apenas R8: preservação forçada ---
# (ProGuard ignora esta diretiva)
-keep,allowobfuscation class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}Após a configuração, execute o build: ./gradlew assembleRelease. Verifique se os arquivos apareceram em build/outputs/mapping/release/: mapping.txt (mapeamento de nomes originais para ofuscados), seeds.txt (classes preservadas pelas regras -keep), usage.txt (classes removidas durante a minificação). O tamanho do APK após a ofuscação deve diminuir de 20 a 50%, dependendo do número de bibliotecas conectadas.
Perguntas Frequentes
R8 é o sucessor do ProGuard, desenvolvido pelo Google. O R8 realiza ofuscação, minificação e otimização em uma única passada, funciona 2–3 vezes mais rápido que o ProGuard e é integrado diretamente ao Android Gradle Plugin. O ProGuard usa quatro fases separadas e requer execução externa. A partir do AGP 7.0, o ProGuard não é usado — o R8 funciona por padrão.
Sim, o R8 usa as mesmas regras do ProGuard (arquivos .pro). As diretivas -keep, -keepclassmembers, -keepattributes, -assumenosideeffects funcionam de forma idêntica. As regras básicas vêm no proguard-android-optimize.txt do Android SDK, enquanto as regras específicas de bibliotecas (Retrofit, Room, Gson) são adicionadas no proguard-rules.pro do projeto. Sem essas regras, o R8 pode remover classes necessárias para bibliotecas que funcionam através de reflection.
R8 está habilitado por padrão no Android Gradle Plugin a partir do AGP 3.4. Para ativar a minificação, defina isMinifyEnabled = true no bloco release buildType do arquivo build.gradle.kts. A flag adicional isShrinkResources = true ativa a remoção de recursos não utilizados. No gradle.properties, você pode desabilitar o R8 forçadamente via android.enableR8=false, mas isso não é recomendado — o R8 é mais rápido e estável.
Ofuscação — renomeação de classes, métodos e campos para nomes curtos sem significado (a, b, c). A classe com.example.app.auth.LoginManager torna-se a.a.a, o método authenticateUser torna-se a. Isso dificulta a engenharia reversa do aplicativo, mas não afeta a lógica de execução. O ProGuard e o R8 renomeiam apenas os elementos não protegidos por regras -keep. O arquivo de mapeamento preserva a correspondência de nomes originais e ofuscados para decodificar logs de falhas.
Para decodificar um stack trace, use o utilitário retrace (parte do SDK ProGuard/R8). Comando: retrace mapping.txt crash-stacktrace.txt. O arquivo de mapeamento está localizado em build/outputs/mapping/release/mapping.txt. O Google Play Console também suporta o upload de mapping.txt ao publicar um AAB — os logs de falha são decodificados automaticamente no console. Sem um arquivo de mapeamento, o stack trace conterá apenas nomes ofuscados como a.b.c(), o que é inútil para depuração.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também