ProGuard/R8: Ofuscação e Proteção de Aplicativos Android

Autor: IT Sectr Publicado: 2026-02-14 Tempo de leitura: 8 min

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 — ferramenta de ofuscação e otimização de bytecode Java, padrão para Android desde os anos 2000
  • R8 — sucessor do ProGuard pelo Google, integrado ao AGP, realiza ofuscação, minificação e otimização em uma única passada
  • Ofuscação renomeia classes e métodos para nomes curtos, dificultando a engenharia reversa do aplicativo
  • Minificação remove classes, métodos e campos não utilizados, reduzindo o tamanho final do APK/AAB
  • Regras do ProGuard (arquivos .pro) controlam quais partes do código são preservadas, ofuscadas ou removidas

O que é ProGuard?

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.

Arquitetura do ProGuard

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 ProGuardPropósitoResultado
ShrinkAnálise do grafo de chamadas e remoção de código mortoMenos classes no APK
OptimizeInlining de métodos, remoção de parâmetros não utilizadosExecução de código mais rápida
ObfuscateRenomeação de classes, campos e métodosProteção contra engenharia reversa
PreverifyAdição de atributos StackMap para JVMCompatibilidade com Java 6+

O que é R8?

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.

kotlin
// 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 de Código no Android

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.

Por que a Ofuscação é Necessária

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.

Exemplo de Regras ProGuard

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.

pro
# =====================
# 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 e ShrinkResources

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.

ShrinkResources em Ação

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.

xml
<!-- 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.

DiretivaPropósitoExemplo
-keepPreserva a classe e todos os seus membros-keep class com.example.api.** { *; }
-keepclassmembersPreserva apenas os membros da classe-keepclassmembers class * { @SerializedName <fields>; }
-keepattributesPreserva metadados do bytecode-keepattributes *Annotation*, Signature
-assumenosideeffectsRemove chamadas sem efeitos colaterais-assumenosideeffects class Log { d(...); }
-dontwarnSuprime avisos-dontwarn com.example.legacy.**

R8 vs ProGuard: Principais Diferenças

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.

Tabela Comparativa

CaracterísticaProGuardR8
DesenvolvedorGuardSquare (Eric Lafarge)Google
Ano de lançamento20022018 (estável em 2019)
Arquitetura4 fases separadas (shrink → optimize → obfuscate → preverify)Única passada: shrink + optimize + obfuscate simultaneamente
Integração no AGPFerramenta externa, executada após javacIntegrada ao compilador D8 DEX
Velocidade de compilação2–3 vezes mais lentoMais rápido devido à passada única e integração nativa
Suporte a KotlinLimitado (problemas com inline, lambdas, coroutines)Completo: coroutines, funções inline, data class
Arquivo de mapeamentomapping.txt (compatível com retrace)mapping.txt (mesmo formato)
Personalização de otimização60+ opções -optimizationpasses, -optimizationsLimitada: a maioria das otimizações ativadas por padrão
Status de suporteSubstituído pelo R8 (AGP 7.0+ não usa)Desenvolvimento ativo, parte do AOSP

Quando o R8 Pode Quebrar o Build

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.

pro
# 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.

Configuração de Regras ProGuard

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.

Passo 1: Configuração Básica

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.

Passo 2: Bibliotecas

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.

Passo 3: Teste do Build de Lançamento

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.

Passo 4: Arquivo de Mapeamento e CI

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.

pro
# ===========================================
# 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

Como o R8 difere do ProGuard?

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.

Preciso escrever regras ProGuard ao usar o R8?

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.

Como habilitar o R8 em um projeto Android?

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.

O que é ofuscação de código no Android?

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.

Como depurar um log de falha de um aplicativo ofuscado?

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

  • ProGuard — uma ferramenta clássica de ofuscação e otimização de bytecode Java, consistindo em quatro fases sequenciais
  • R8 — um sucessor moderno do Google, integrado ao AGP, realizando todas as fases em uma única passada com desempenho 2–3 vezes superior
  • Ofuscação renomeia classes, métodos e campos para nomes curtos, dificultando a engenharia reversa e protegendo a lógica comercial do aplicativo
  • Minificação remove código e recursos não utilizados, reduzindo o tamanho do APK em 20–50% em projetos típicos
  • Regras do ProGuard (arquivos .pro) controlam o comportamento da ofuscação — as diretivas -keep, -keepclassmembers, -assumenosideeffects especificam quais elementos são preservados, removidos ou renomeados
  • Arquivo de mapeamento (mapping.txt) é um artefato de build criticamente importante para decodificar logs de falhas de builds de lançamento via retrace
  • Teste do build de lançamento em um dispositivo real é obrigatório — problemas de ofuscação só se manifestam em tempo de execução e exigem a adição de regras -keep faltantes

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.

Discutir o projeto

Leia também