ProGuard/R8: de essentie, obfuscatie en beveiliging van Android-apps

Auteur: IT Sectr Gepubliceerd: 2026-02-14 Leestijd: 8 min

ProGuard en R8 — tools voor obfuscatie, minificatie en optimalisatie voor Android-apps. ProGuard, gemaakt in 2002, was lange tijd de de facto standaard voor de bescherming van Java-code. R8 — zijn opvolger, ontwikkeld door Google en ingebouwd in Android Gradle Plugin vanaf AGP 3.4. Beide tools verkleinen de APK-grootte, verwijderen dode code en bemoeilijken reverse engineering. Volgens Android Developers voert R8 de build 2–3 keer sneller uit dan ProGuard bij vergelijkbare obfuscatiekwaliteit.

Belangrijkste punten

  • ProGuard — tool voor obfuscatie en optimalisatie van Java-bytecode, standaard voor Android sinds de jaren 2000
  • R8 — opvolger van ProGuard van Google, ingebouwd in AGP, voert obfuscatie, minificatie en optimalisatie in één keer uit
  • Obfuscatie hernoemt klassen en methoden naar korte namen, waardoor reverse engineering van de app wordt bemoeilijkt
  • Minificatie verwijdert ongebruikte klassen, methoden en velden, waardoor de uiteindelijke APK/AAB kleiner wordt
  • ProGuard rules (.pro-bestanden) bepalen welke delen van de code worden bewaard, geobfusceerd of verwijderd

Wat is ProGuard?

ProGuard — is een open-source tool (Apache 2.0) voor obfuscatie, minificatie, optimalisatie en preverificatie van Java-bytecode. Ontwikkeld door Eric Lafourge in 2002 in het kader van het SourceForge-project. ProGuard neemt gecompileerde Java-klassen (.class) of JAR-archieven als invoer en levert verwerkte klassen van hetzelfde formaat, maar kleiner en met hernoemde elementen.

ProGuard was lange tijd de enige standaard voor de bescherming van Android-apps tegen reverse engineering. Google beval het gebruik ervan officieel aan in Android SDK en leverde de standaardconfiguratie in het bestand proguard-android-optimize.txt in de SDK tools. ProGuard werkte als een aparte tool, gestart na compilatie van Java-code naar bytecode en vóór het verpakken naar DEX.

ProGuard-architectuur

ProGuard bestaat uit vier opeenvolgende fasen: shrink (verwijderen van ongebruikte klassen), optimize (optimalisatie van bytecode — inlining, verwijderen van dode code), obfuscate (hernoemen van klassen, methoden en velden naar korte namen), preverify (controleren van compatibiliteit met JVM). Elke fase wordt aangestuurd door afzonderlijke regels uit configuratiebestanden.

In de obfuscatie-fase genereert ProGuard een mapping-bestand (mapping.txt) dat de oorspronkelijke namen toewijst aan geobfusceerde namen. Dit bestand is cruciaal voor het decoderen van crashlogs uit release-builds met de tool retrace. Zonder mapping-bestand wordt de stack trace een reeks letters a(), b(), c() zonder mogelijkheid om de oorspronkelijke context te herstellen.

ProGuard-faseDoelResultaat
ShrinkAnalyse van de aanroepgraaf en verwijderen van dode codeVermindering van het aantal klassen in APK
OptimizeInlinen van methoden, verwijderen van ongebruikte parametersVersnelling van code-uitvoering
ObfuscateHernoemen van klassen, velden en methodenBescherming tegen reverse engineering
PreverifyToevoegen van StackMap-attributen voor JVMCompatibiliteit met Java 6+

Wat is R8?

R8 — is de volgende generatie obfuscatie- en minificatietool van Google, voor het eerst geïntroduceerd in Android Studio 3.3 (november 2018) en standaard geworden in AGP 3.4 (augustus 2019). In tegenstelling tot ProGuard maakt R8 deel uit van de D8/R8-compiler die Java-bytecode omzet naar DEX-formaat. R8 voert alle fasen — obfuscatie, minificatie en optimalisatie — in één keer uit, zonder tussenbestanden tussen tools.

Google heeft R8 ontwikkeld met twee doelen: de build versnellen (ProGuard werkte als externe tool) en naadloze integratie met de moderne Android-stack (Desugar, Core Library Desugaring, D8) garanderen. R8 is geschreven in Kotlin en Java en maakt deel uit van de R8/Desugar-repository in AOSP (Android Open Source Project).

Een belangrijk voordeel van R8 — volledige achterwaartse compatibiliteit met ProGuard rules. Bestaande .pro-bestanden werken zonder wijzigingen. R8 ondersteunt zelfs specifieke ProGuard-directieven, waaronder -whyareyoukeeping, -printconfiguration en -printmapping. Dit betekent dat de overstap van ProGuard naar R8 transparant verloopt: het volstaat om AGP te updaten.

kotlin
// build.gradle.kts — R8 inschakelen via minifyEnabled
android {
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            isShrinkResources = true

            proguardFiles(
                // Basisconfiguratie uit Android SDK
                getDefaultProguardFile("proguard-android-optimize.txt"),
                // Aangepaste projectregels
                "proguard-rules.pro"
            )
        }
    }
}

De code toont de standaardconfiguratie van een release-build. De vlag isMinifyEnabled = true activeert R8 voor obfuscatie en optimalisatie. isShrinkResources = true verwijdert bovendien ongebruikte bronnen. getDefaultProguardFile laadt de basisregels uit de SDK, en proguard-rules.pro bevat projectspecifieke instellingen.

Code-obfuscatie in Android

Obfuscatie — is het proces van het omzetten van broncode naar een vorm die moeilijk te analyseren is voor mensen, maar die volledige functionaliteit behoudt. In de Android-context betekent obfuscatie het hernoemen van klassen, methoden en velden naar korte, betekenisloze namen: com.example.app.auth.LoginManager wordt a.a.a, de methode authenticateUser wordt a, het veld userToken wordt b.

Waarom obfuscatie nodig is

Android APK-bestanden zijn archieven die met elke archiver (ZIP, 7z, WinRAR) kunnen worden geopend. Zonder obfuscatie krijgt een aanvaller de volledige kaart van de app: pakket-, klasse-, methode- en veldnamen. Tools zoals jadx of Bytecode Viewer herstellen bijna de originele Java-code uit DEX-bestanden in enkele seconden. Obfuscatie maakt de code niet onkwetsbaar, maar verhoogt de drempel aanzienlijk: in plaats van betekenisvolle namen ziet de lezer a(), b(), c().

Typische doelen van obfuscatie: bescherming van commerciële logica (algoritmen, berekeningsformules), bemoeilijken van diefstal van API-sleutels en tokens, voorkomen van klassevervanging via reflection, bescherming tegen patching en modificatie van APK (repackage attack). In de praktijk lost 70% van de taken juist het hernoemen op — daarom wordt ProGuard / R8 gestart.

Voorbeeld van ProGuard-regels

Hieronder staat een typisch proguard-rules.pro-bestand voor een Android-project met Retrofit, Gson en Parcelable. De -keep-regels behouden de klassen en methoden die nodig zijn voor de werking van bibliotheken via reflection. Zonder deze regels verwijdert of hernoemt R8 de klassen waartoe de bibliotheek via een stringnaam toegang krijgt.

pro
# =====================
# Retrofit — interfaces behouden
# =====================
-keep,allowobfuscation,allowshrinking interface retrofit2.** { *; }
-keepattributes Signature, Exceptions

# =====================
# Gson — JSON-serialisatie
# =====================
-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 — logs verwijderen uit release
# =====================
-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(...);
}

# =====================
# Kotlin data-klassen — constructors behouden
# =====================
-keepclassmembers class * {
    @kotlin.Metadata <fields>;
}

# =====================
# Activity — ingangspunt
# =====================
-keep class * extends android.app.Activity {
    @android.annotation.SuppressLint <methods>;
}

Elk directive in het .pro-bestand lost een specifieke taak op. -keep voorkomt het verwijderen of hernoemen van een hele klasse. -keepclassmembers beschermt alleen de leden van de klasse (velden en methoden), maar laat verwijdering van de klasse zelf toe als deze niet wordt gebruikt. -assumenosideeffects geeft R8 aan dat een methodeaanroep geen bijwerkingen heeft en veilig kan worden verwijderd. Het directive -keepattributes behoudt metadata in de bytecode — annotaties, handtekeningen, uitzonderingen.

De regel -keep,allowobfuscation,allowshrinking voor Retrofit staat R8 toe interfaces te hernoemen, maar niet te verwijderen. Dit is noodzakelijk omdat Retrofit via dynamische proxy (java.lang.reflect.Proxy) toegang krijgt tot interfaces en verwijdering leidt tot ClassNotFoundException in runtime. Evenzo gebruikt Gson reflection voor toegang tot velden met @SerializedName-annotatie — zonder -keepclassmembers worden velden als ongebruikt verwijderd.

Minificatie en ShrinkResources

Minificatie (shrinking) — het proces van het verwijderen van ongebruikte code en bronnen uit de uiteindelijke build. ProGuard en R8 analyseren de aanroepgraaf vanaf de ingangspunten (Activity, Service, BroadcastReceiver) en verwijderen klassen en methoden die niet via de aanroepketen bereikt kunnen worden. ShrinkResources — een extra fase die ongebruikte bronnen uit res/ (layout, drawable, string, color) verwijdert.

Minificatie levert de grootste winst op in grote projecten met bibliotheken. Typisch beeld: het project gebruikt 10% van de code uit een aangesloten bibliotheek (bijv. Google Play Services). Zonder minificatie komt alle code van de bibliotheek in de APK terecht. Met minificatie verwijdert R8 70–90% van de bibliotheekcode en laat alleen daadwerkelijk gebruikte klassen en methoden over. Dit heeft directe invloed op de APK-grootte, laadtijd en geheugengebruik.

ShrinkResources in actie

Het mechanisme ShrinkResources werkt samen met codeminificatie. Nadat R8 heeft bepaald welke klassen worden gebruikt, analyseert de resource-shrinking verwijzingen naar bronnen uit de code: R.layout.main, R.drawable.icon, getString(R.string.title). Alle bronnen waarnaar geen directe of indirecte verwijzing bestaat, worden verwijderd uit de uiteindelijke APK of AAB. Hiervoor wordt het bronnenbestand resources.arsc en de mappen res/ gebruikt.

Een belangrijke nuance: bronnen kunnen via getIdentifier() of Resources.getResourceName() op stringnaam worden aangeroepen, waarbij de R-klasse wordt omzeild. In dergelijke gevallen ziet R8 de directe koppeling niet en kan het een bron verwijderen die daadwerkelijk wordt gebruikt. Voor de bescherming van dergelijke bronnen bestaat het directive -keep class **.R$* { *; } — het behoudt alle identificaties van de R-klasse.

xml
<!-- Voorbeeld: bron die alleen via getIdentifier() wordt gebruikt -->
<string name="dynamic_title_welcome">Welkom</string>
<string name="dynamic_title_share">Delen</string>

<!-- Kotlin-code die via string benadert -->
<!-- val title = getString(resources.getIdentifier( -->
<!--     \"dynamic_title_${type}\", \"string\", packageName)) -->

In dit geval ziet R8 geen statische verwijzing naar dynamic_title_welcome in de R-klasse, omdat de toegang via getIdentifier met een dynamische naam plaatsvindt. Om dergelijke bronnen te behouden, moet in proguard-rules.pro het directive -keepclassmembers class **.R$string { *; } worden toegevoegd — het verbiedt het verwijderen van velden uit alle R$string-klassen.

DirectiveDoelVoorbeeld
-keepBehoudt de klasse en al zijn leden-keep class com.example.api.** { *; }
-keepclassmembersBehoudt alleen de leden van de klasse-keepclassmembers class * { @SerializedName <fields>; }
-keepattributesBehoudt metadata van bytecode-keepattributes *Annotation*, Signature
-assumenosideeffectsVerwijdert aanroepen zonder bijwerkingen-assumenosideeffects class Log { d(...); }
-dontwarnOnderdrukt waarschuwingen-dontwarn com.example.legacy.**

R8 vs ProGuard: belangrijkste verschillen

Hoewel R8 de opvolger is van ProGuard, zijn er fundamentele verschillen in architectuur, prestaties en gedrag tussen de tools. Google heeft de ondersteuning voor ProGuard in Android Gradle Plugin officieel stopgezet vanaf AGP 7.0, maar ProGuard wordt nog steeds gebruikt in projecten waar specifiek optimalisatiegedrag vereist is dat niet beschikbaar is in R8.

Vergelijkingstabel

KenmerkProGuardR8
OntwikkelaarGuardSquare (Eric Lafourge)Google
Jaar van uitgave20022018 (stabiel in 2019)
Architectuur4 aparte fasen (shrink → optimize → obfuscate → preverify)Eén keer: shrink + optimize + obfuscate gelijktijdig
Integratie in AGPExterne tool, gestart na javacIngebouwd in D8 DEX-compiler
Buildsnelheid2–3 keer langzamerSneller door één keer en native integratie
Kotlin-ondersteuningBeperkt (problemen met inline, lambdas, coroutines)Volledig: coroutines, inline-functies, data class
Mapping-bestandmapping.txt (compatibel met retrace)mapping.txt (zelfde formaat)
Aanpassing optimalisatie60+ opties -optimizationpasses, -optimizationsBeperkt: meeste optimalisaties standaard ingeschakeld
OndersteuningsstatusVervangen door R8 (AGP 7.0+ gebruikt niet)Actieve ontwikkeling, onderdeel van AOSP

Wanneer R8 de build kan breken

R8 verwijdert agressiever dan ProGuard code die het als dood beschouwt. Dit leidt tot situaties waarin de debug-build werkt, maar de release-build crasht met ClassNotFoundException of NoSuchMethodException. Typische gevallen: bibliotheken die reflection op klassenaam gebruiken (Gson, Moshi, Retrofit, Room, Dagger); aanroepen van ServiceLoader of java.util.ServiceLoader; dynamische proxies (java.lang.reflect.Proxy); native methoden (JNI). Oplossing — voeg -keep toe voor alle klassen die via reflection worden aangeroepen.

pro
# Typische reflection-problemen — R8 ziet geen statische koppeling

# Room — DAO en migraties behouden
-keep class * extends androidx.room.RoomDatabase { *; }
-keep class *.DatabaseMigrations { *; }

# Dagger / Hilt — componenten behouden
-keep class * extends dagger.hilt.android.components.** { *; }

# JNI — native methoden niet hernoemen
-keepclasseswithmembernames class * {
    native <methods>;
}

# Data Binding — Binding-klassen behouden
-keep class *.databinding.** { *; }

Als de build na het toevoegen van regels nog steeds crasht, gebruik dan de vlag -printconfiguration full-config.txt in proguard-rules.pro. R8 genereert een volledig configuratiebestand dat laat zien welke regels zijn toegepast en welke klassen worden behouden. Ook nuttig is het directive -whyareyoukeeping class com.example.MyClass — het geeft de reden waarom R8 heeft besloten de betreffende klasse te behouden.

ProGuard rules instellen

Het correct instellen van ProGuard rules — de sleutel tot stabiele obfuscatie zonder bugs in runtime. Hieronder staat het stapsgewijze proces voor het instellen voor een nieuw project of voor een project waarin obfuscatie fouten veroorzaakt.

Stap 1: Basisconfiguratie

Begin met het aansluiten van het standaard Android SDK-bestand — proguard-android-optimize.txt. Het bevat regels voor basis Android-componenten: Activity, Service, BroadcastReceiver, ContentProvider, View, Fragment. Dit bestand bevindt zich in de SDK-map: $ANDROID_HOME/tools/proguard/proguard-android-optimize.txt. Als u AGP gebruikt, laadt getDefaultProguardFile het automatisch.

Stap 2: Bibliotheken

Elke populaire bibliotheek heeft aanbevolen ProGuard-regels. Retrofit, OkHttp, Glide, Fresco, Coil, Room, Dagger/Hilt, Kotlin Coroutines — ze vereisen allemaal specifieke -keep-regels. Meestal zijn de regels opgenomen in de AAR-bibliotheek en worden ze automatisch aangesloten via consumer guard rules. Controleer of de bibliotheek het bestand proguard.txt in de AAR levert — dit is een teken dat de regels al in aanmerking zijn genomen.

Stap 3: Testen van release-build

Test vóór publicatie de release-build verplicht op een echt apparaat of emulator. Obfuscatieproblemen manifesteren zich alleen in runtime. Controleer: authenticatie (aanmelden/registreren), gegevens laden uit het netwerk, navigatie tussen schermen, camera en galerij, pushmeldingen, Deeplinks, WebView. Elke crash in de release-build moet worden gedecodeerd via retrace met het mapping-bestand en er moeten ontbrekende -keep-regels worden toegevoegd.

Stap 4: Mapping-bestand en CI

Het mapping-bestand wordt gegenereerd in build/outputs/mapping/release/mapping.txt. Dit bestand is verplicht om te bewaren: zonder is het onmogelijk om crashlogs uit Google Play Console te decoderen. Neem mapping.txt op in het versiebeheersysteem of upload het als CI-artefact. Google Play Console accepteert het mapping-bestand automatisch bij het uploaden van AAB met ingeschakelde uploading mapping.txt.

Hieronder staat de volledige workflow voor het instellen van obfuscatie in het bestand proguard-rules.pro met opmerkingen voor elke groep regels.

pro
# ===========================================
# proguard-rules.pro — volledig voorbeeld
# ===========================================

# --- Algemene instellingen ---
-keepattributes *Annotation*, Signature, Exceptions, InnerClasses, EnclosingMethod
-dontpreverify

# --- Android-componenten ---
-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 {}

# --- Serialisatie ---
-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();
}

# --- Alleen R8: geforceerd behouden ---
# (ProGuard negeert dit directive)
-keep,allowobfuscation class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator CREATOR;
}

Voer na het instellen de build uit: ./gradlew assembleRelease. Controleer of in build/outputs/mapping/release/ de bestanden zijn verschenen: mapping.txt (overeenkomst van originele en geobfusceerde namen), seeds.txt (klassen behouden door -keep-regels), usage.txt (klassen verwijderd bij minificatie). De APK-grootte na obfuscatie zou met 20–50% moeten afnemen, afhankelijk van het aantal aangesloten bibliotheken.

Veelgestelde vragen

Hoe verschilt R8 van ProGuard?

R8 — de opvolger van ProGuard, ontwikkeld door Google. R8 voert obfuscatie, minificatie en optimalisatie in één keer uit, werkt 2–3 keer sneller dan ProGuard en is direct geïntegreerd in Android Gradle Plugin. ProGuard gebruikt vier aparte fasen en vereist externe lancering. Vanaf AGP 7.0 wordt ProGuard niet meer gebruikt — standaard werkt R8.

Moet ik ProGuard rules schrijven bij gebruik van R8?

Ja, R8 gebruikt dezelfde ProGuard rules (.pro-bestanden). De directives -keep, -keepclassmembers, -keepattributes, -assumenosideeffects werken identiek. De basisregels komen uit proguard-android-optimize.txt van Android SDK, en specifieke voor bibliotheken (Retrofit, Room, Gson) worden toegevoegd in proguard-rules.pro van het project. Zonder deze regels kan R8 klassen verwijderen die nodig zijn voor de werking van bibliotheken via reflection.

Hoe schakel ik R8 in een Android-project in?

R8 is standaard ingeschakeld in Android Gradle Plugin vanaf AGP 3.4. Om minificatie te activeren, stelt u isMinifyEnabled = true in in het release buildType-blok van build.gradle.kts. De extra vlag isShrinkResources = true schakelt het verwijderen van ongebruikte bronnen in. In gradle.properties kan R8 worden uitgeschakeld via android.enableR8=false, maar dit wordt niet aanbevolen — R8 is sneller en stabieler.

Wat is code-obfuscatie in Android?

Obfuscatie — het hernoemen van klassen, methoden en velden naar korte betekenisloze namen (a, b, c). De klasse com.example.app.auth.LoginManager wordt a.a.a, de methode authenticateUser wordt a. Dit bemoeilijkt reverse engineering van de app, maar heeft geen invloed op de uitvoeringslogica. ProGuard en R8 hernoemen alleen elementen die niet worden beschermd door -keep-regels. Het mapping-bestand behoudt de overeenkomst van originele en geobfusceerde namen voor het decoderen van crashlogs.

Hoe debug ik een crashlog uit een geobfusceerde app?

Voor het decoderen van stack traces wordt de tool retrace (onderdeel van ProGuard/R8 SDK) gebruikt. Commando: retrace mapping.txt crash-stacktrace.txt. Het mapping-bestand bevindt zich in build/outputs/mapping/release/mapping.txt. Google Play Console ondersteunt ook het uploaden van mapping.txt bij publicatie van AAB — crashlogs worden automatisch gedecodeerd in de console. Zonder mapping-bestand bevat de stack trace alleen geobfusceerde namen a.b.c(), wat nutteloos is voor debugging.

Samenvatting

  • ProGuard — klassieke tool voor obfuscatie en optimalisatie van Java-bytecode, bestaande uit vier opeenvolgende fasen
  • R8 — moderne opvolger van Google, ingebouwd in AGP, voert alle fasen in één keer uit met 2–3 keer hogere prestaties
  • Obfuscatie hernoemt klassen, methoden en velden naar korte namen, bemoeilijkt reverse engineering en beschermt de commerciële logica van de app
  • Minificatie verwijdert ongebruikte code en bronnen, verkleint de APK met 20–50% in typische projecten
  • ProGuard rules (.pro-bestanden) bepalen het gedrag van obfuscatie — de directives -keep, -keepclassmembers, -assumenosideeffects specificeren welke elementen worden behouden, verwijderd of hernoemd
  • Mapping-bestand (mapping.txt) — cruciaal build-artefact voor het decoderen van crashlogs uit release-builds via retrace
  • Testen van de release-build op een echt apparaat is verplicht — obfuscatieproblemen manifesteren zich alleen in runtime en vereisen het toevoegen van ontbrekende -keep-regels

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook