ProGuard/R8: essensen, obfuskering och skydd av Android-appar

Författare: IT Sectr Publicerad: 2026-02-14 Lästid: 8 min

ProGuard och R8 — verktyg för obfuskering, minifiering och optimering för Android-appar. ProGuard, skapat 2002, var länge de facto-standarden för skydd av Java-kod. R8 — dess efterträdare, utvecklad av Google och inbyggd i Android Gradle Plugin från och med AGP 3.4. Båda verktygen minskar APK-storleken, tar bort död kod och försvårar reverse engineering. Enligt Android Developers utför R8 bygget 2–3 gånger snabbare än ProGuard med jämförbar obfuskeringskvalitet.

Huvudpunkter

  • ProGuard — verktyg för obfuskering och optimering av Java-bytekod, standard för Android sedan 2000-talet
  • R8 — efterträdare till ProGuard från Google, inbyggd i AGP, utför obfuskering, minifiering och optimering i en enda passage
  • Obfuskering byter namn på klasser och metoder till korta namn, vilket försvårar reverse engineering av appen
  • Minifiering tar bort oanvända klasser, metoder och fält, vilket minskar storleken på den slutliga APK/AAB
  • ProGuard rules (.pro-filer) styr vilka delar av koden som bevaras, obfuskeras eller tas bort

Vad är ProGuard?

ProGuard — är ett öppen källkodsverktyg (Apache 2.0) för obfuskering, minifiering, optimering och förhandskontroll av Java-bytekod. Utvecklat av Eric Lafourge 2002 inom ramen för SourceForge-projektet. ProGuard tar emot kompilerade Java-klasser (.class) eller JAR-arkiv som indata och producerar bearbetade klasser av samma format, men med mindre storlek och omdöpta element.

ProGuard var länge den enda standarden för att skydda Android-appar mot reverse engineering. Google rekommenderade officiellt dess användning i Android SDK och levererade standardkonfigurationen i filen proguard-android-optimize.txt i SDK tools. ProGuard fungerade som ett separat verktyg som kördes efter kompilering av Java-kod till bytekod och före paketering till DEX.

ProGuard-arkitektur

ProGuard består av fyra på varandra följande faser: shrink (borttagning av oanvända klasser), optimize (optimering av bytekod — inlining, borttagning av död kod), obfuscate (omdöpning av klasser, metoder och fält till korta namn), preverify (kontroll av kompatibilitet med JVM). Varje fas styrs av separata regler från konfigurationsfiler.

I obfuskeringsfasen genererar ProGuard en mapping-fil (mapping.txt) som mappar ursprungliga namn till obfuskerade namn. Denna fil är avgörande för att avkoda crashloggar från release-byggen med verktyget retrace. Utan mapping-fil förvandlas stack trace till en uppsättning bokstäver a(), b(), c() utan möjlighet att återställa det ursprungliga sammanhanget.

ProGuard-fasSyfteResultat
ShrinkAnalys av anropsgraf och borttagning av död kodMinskning av antalet klasser i APK
OptimizeInlining av metoder, borttagning av oanvända parametrarSnabbare kodutförande
ObfuscateOmdöpning av klasser, fält och metoderSkydd mot reverse engineering
PreverifyLägga till StackMap-attribut för JVMKompatibilitet med Java 6+

Vad är R8?

R8 — är nästa generations obfuskering och minifieringsverktyg från Google, först introducerat i Android Studio 3.3 (november 2018) och blev standard i AGP 3.4 (augusti 2019). Till skillnad från ProGuard är R8 en del av D8/R8-kompilatorn som omvandlar Java-bytekod till DEX-format. R8 utför alla faser — obfuskering, minifiering och optimering — i en enda passage, utan att överföra mellanliggande filer mellan verktyg.

Google utvecklade R8 med två mål: snabba upp bygget (ProGuard fungerade som externt verktyg) och säkerställa sömlös integration med den moderna Android-stacken (Desugar, Core Library Desugaring, D8). R8 är skrivet i Kotlin och Java och är en del av arkivet R8/Desugar i AOSP (Android Open Source Project).

En viktig fördel med R8 — full bakåtkompatibilitet med ProGuard rules. Befintliga .pro-filer fungerar utan ändringar. R8 stöder till och med ProGuard-specifika direktiv, inklusive -whyareyoukeeping, -printconfiguration och -printmapping. Detta innebär att övergången från ProGuard till R8 sker transparent: det räcker med att uppdatera AGP.

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

            proguardFiles(
                // Grundkonfiguration från Android SDK
                getDefaultProguardFile("proguard-android-optimize.txt"),
                // Anpassade projektregler
                "proguard-rules.pro"
            )
        }
    }
}

Koden visar standardkonfigurationen för ett release-bygge. Flaggan isMinifyEnabled = true aktiverar R8 för obfuskering och optimering. isShrinkResources = true tar dessutom bort oanvända resurser. getDefaultProguardFile laddar basreglerna från SDK och proguard-rules.pro innehåller projektspecifika inställningar.

Kodobfuskering i Android

Obfuskering — är processen att omvandla källkod till en form som är svår för människor att analysera men som behåller full funktionalitet. I Android-sammanhang innebär obfuskering att byta namn på klasser, metoder och fält till korta, meningslösa namn: com.example.app.auth.LoginManager blir a.a.a, metoden authenticateUser blir a, fältet userToken blir b.

Varför obfuskering behövs

Android APK-filer är arkiv som kan öppnas med vilket arkiveringsprogram som helst (ZIP, 7z, WinRAR). Utan obfuskering får en angripare en fullständig karta över appen: paket-, klass-, metod- och fältnamn. Verktyg som jadx eller Bytecode Viewer återställer nästan original Java-koden från DEX-filer på några sekunder. Obfuskering gör inte koden osårbar, men höjer tröskeln avsevärt: istället för meningsfulla namn ser läsaren a(), b(), c().

Typiska mål för obfuskering: skydd av kommersiell logik (algoritmer, beräkningsformler), försvårande av stöld av API-nycklar och tokens, förhindrande av klassbyte via reflection, skydd mot patchning och modifiering av APK (repackage attack). I praktiken löser 70% av uppgifterna just genom omdöpning — det är därför ProGuard / R8 körs.

Exempel på ProGuard-regler

Nedan är en typisk proguard-rules.pro-fil för ett Android-projekt med Retrofit, Gson och Parcelable. Reglerna -keep bevarar de klasser och metoder som krävs för att biblioteken ska fungera via reflection. Utan dessa regler kommer R8 att ta bort eller byta namn på klasser som biblioteket kommer åt via strängnamn.

pro
# =====================
# Retrofit — bevara gränssnitt
# =====================
-keep,allowobfuscation,allowshrinking interface retrofit2.** { *; }
-keepattributes Signature, Exceptions

# =====================
# Gson — JSON-serialisering
# =====================
-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 — ta bort loggar från 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-klasser — bevara konstruktorer
# =====================
-keepclassmembers class * {
    @kotlin.Metadata <fields>;
}

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

Varje direktiv i .pro-filen löser en specifik uppgift. -keep förhindrar borttagning eller omdöpning av en hel klass. -keepclassmembers skyddar endast klassens medlemmar (fält och metoder) men tillåter borttagning av själva klassen om den inte används. -assumenosideeffects anger för R8 att metodanropet inte har bieffekter och kan tas bort på ett säkert sätt. Direktivet -keepattributes bevarar metadata i bytekoden — annotationer, signaturer, undantag.

Regeln -keep,allowobfuscation,allowshrinking för Retrofit tillåter R8 att byta namn på gränssnitt, men inte att ta bort dem. Detta är nödvändigt eftersom Retrofit kommer åt gränssnitt via dynamisk proxy (java.lang.reflect.Proxy) och borttagning skulle leda till ClassNotFoundException vid körning. På samma sätt använder Gson reflection för åtkomst till fält med @SerializedName-annotation — utan -keepclassmembers kommer fälten att tas bort som oanvända.

Minifiering och ShrinkResources

Minifiering (shrinking) — processen att ta bort oanvänd kod och resurser från det slutliga bygget. ProGuard och R8 analyserar anropsgrafen med början från ingångspunkterna (Activity, Service, BroadcastReceiver) och tar bort klasser och metoder som inte kan nås via anropskedjan. ShrinkResources — en extra fas som tar bort oanvända resurser från res/ (layout, drawable, string, color).

Minifiering ger störst vinst i stora projekt med bibliotek. Typisk bild: projektet använder 10% av koden från ett anslutet bibliotek (t.ex. Google Play Services). Utan minifiering hamnar all bibliotekskod i APK. Med minifiering tar R8 bort 70–90% av bibliotekskoden och lämnar bara faktiskt använda klasser och metoder. Detta påverkar direkt APK-storleken, laddningstiden och minnesförbrukningen.

ShrinkResources i praktiken

Mekanismen ShrinkResources arbetar tillsammans med kodminifiering. Efter att R8 har bestämt vilka klasser som används, analyserar resurskrympningen referenser till resurser från koden: R.layout.main, R.drawable.icon, getString(R.string.title). Alla resurser som inte har en direkt eller indirekt referens tas bort från den slutliga APK eller AAB. För detta används resursfilen resources.arsc och mapparna res/.

En viktig nyans: resurser kan anropas via getIdentifier() eller Resources.getResourceName() med strängnamn, vilket förbigår R-klassen. I sådana fall ser R8 inte den direkta kopplingen och kan ta bort en resurs som faktiskt används. För att skydda sådana resurser finns direktivet -keep class **.R$* { *; } — det bevarar alla identifierare i R-klassen.

xml
<!-- Exempel: resurs som endast används via getIdentifier() -->
<string name="dynamic_title_welcome">Välkommen</string>
<string name="dynamic_title_share">Dela</string>

<!-- Kotlin-kod som kommer åt via sträng -->
<!-- val title = getString(resources.getIdentifier( -->
<!--     \"dynamic_title_${type}\", \"string\", packageName)) -->

I detta fall ser R8 inte den statiska referensen till dynamic_title_welcome i R-klassen eftersom åtkomsten sker via getIdentifier med ett dynamiskt namn. För att bevara sådana resurser måste direktivet -keepclassmembers class **.R$string { *; } läggas till i proguard-rules.pro — det förbjuder borttagning av alla fält från alla R$string-klasser.

DirektivSyfteExempel
-keepBevarar klassen och alla dess medlemmar-keep class com.example.api.** { *; }
-keepclassmembersBevarar endast klassens medlemmar-keepclassmembers class * { @SerializedName <fields>; }
-keepattributesBevarar bytekodens metadata-keepattributes *Annotation*, Signature
-assumenosideeffectsTar bort anrop utan bieffekter-assumenosideeffects class Log { d(...); }
-dontwarnDämpar varningar-dontwarn com.example.legacy.**

R8 vs ProGuard: viktigaste skillnaderna

Trots att R8 är efterträdare till ProGuard finns det grundläggande skillnader i arkitektur, prestanda och beteende mellan verktygen. Google har officiellt avslutat stödet för ProGuard i Android Gradle Plugin från och med AGP 7.0, men ProGuard används fortfarande i projekt där specifikt optimeringsbeteende krävs som inte är tillgängligt i R8.

Jämförelsetabell

EgenskapProGuardR8
UtvecklareGuardSquare (Eric Lafourge)Google
Utgivningsår20022018 (stabilt 2019)
Arkitektur4 separata faser (shrink → optimize → obfuscate → preverify)En passage: shrink + optimize + obfuscate samtidigt
Integrering i AGPExternt verktyg, körs efter javacInbyggd i D8 DEX-kompilatorn
Bygghastighet2–3 gånger långsammareSnabbare tack vare en passage och inbyggd integrering
Kotlin-stödBegränsat (problem med inline, lambdas, coroutines)Fullt: coroutines, inline-funktioner, data class
Mapping-filmapping.txt (kompatibel med retrace)mapping.txt (samma format)
Anpassning av optimering60+ alternativ -optimizationpasses, -optimizationsBegränsad: de flesta optimeringar är aktiverade som standard
SupportstatusErsatt av R8 (AGP 7.0+ använder inte)Aktiv utveckling, del av AOSP

När R8 kan bryta bygget

R8 tar bort kod som det anser vara död mer aggressivt än ProGuard. Detta leder till situationer där debug-bygget fungerar men release kraschar med ClassNotFoundException eller NoSuchMethodException. Typiska fall: bibliotek som använder reflection på klassnamn (Gson, Moshi, Retrofit, Room, Dagger); anrop av ServiceLoader eller java.util.ServiceLoader; dynamiska proxys (java.lang.reflect.Proxy); inbyggda metoder (JNI). Lösning — lägg till -keep för alla klasser som anropas via reflection.

pro
# Typiska problem med reflection — R8 ser inte statisk koppling

# Room — bevara DAO och migreringar
-keep class * extends androidx.room.RoomDatabase { *; }
-keep class *.DatabaseMigrations { *; }

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

# JNI — byt inte namn på inbyggda metoder
-keepclasseswithmembernames class * {
    native <methods>;
}

# Data Binding — bevara Binding-klasser
-keep class *.databinding.** { *; }

Om bygget fortfarande kraschar efter att reglerna har lagts till, använd flaggan -printconfiguration full-config.txt i proguard-rules.pro. R8 genererar en fullständig konfigurationsfil som visar vilka regler som har tillämpats och vilka klasser som bevaras. Även direktivet -whyareyoukeeping class com.example.MyClass är användbart — det visar orsaken till varför R8 beslutade att bevara den klassen.

Konfigurera ProGuard rules

Korrekt konfiguration av ProGuard rules — nyckeln till stabil obfuskering utan buggar vid körning. Nedan är steg-för-steg-processen för konfiguration för ett nytt projekt eller för ett projekt där obfuskering orsakar fel.

Steg 1: Grundkonfiguration

Börja med att ansluta standardfilen för Android SDK — proguard-android-optimize.txt. Den innehåller regler för grundläggande Android-komponenter: Activity, Service, BroadcastReceiver, ContentProvider, View, Fragment. Denna fil finns i SDK-mappen: $ANDROID_HOME/tools/proguard/proguard-android-optimize.txt. Om du använder AGP laddar getDefaultProguardFile den automatiskt.

Steg 2: Bibliotek

Varje populärt bibliotek har rekommenderade ProGuard-regler. Retrofit, OkHttp, Glide, Fresco, Coil, Room, Dagger/Hilt, Kotlin Coroutines — alla kräver specifika -keep-regler. Vanligtvis ingår reglerna i AAR-biblioteket och ansluts automatiskt via consumer guard rules. Kontrollera om biblioteket tillhandahåller filen proguard.txt i AAR — detta är ett tecken på att reglerna redan är beaktade.

Steg 3: Testning av release-bygge

Före publicering, testa release-bygget obligatoriskt på en verklig enhet eller emulator. Obfuskeringsproblem uppträder endast vid körning. Kontrollera: autentisering (inloggning/registrering), laddning av data från nätverket, navigering mellan skärmar, kamera och galleri, push-meddelanden, Deeplinks, WebView. Varje krasch i release-bygget måste avkodas via retrace med mapping-filen och saknade -keep-regler måste läggas till.

Steg 4: Mapping-fil och CI

Mapping-filen genereras i build/outputs/mapping/release/mapping.txt. Denna fil måste sparas: utan den går det inte att avkoda crashloggar från Google Play Console. Inkludera mapping.txt i versionshanteringssystemet eller ladda upp den som CI-artefakt. Google Play Console accepterar mapping-filen automatiskt vid uppladdning av AAB med aktiverad uploading mapping.txt.

Nedan är det fullständiga arbetsflödet för konfiguration av obfuskering i filen proguard-rules.pro med kommentarer för varje regelgrupp.

pro
# ===========================================
# proguard-rules.pro — fullständigt exempel
# ===========================================

# --- Allmänna inställningar ---
-keepattributes *Annotation*, Signature, Exceptions, InnerClasses, EnclosingMethod
-dontpreverify

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

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

# --- Endast R8: tvingad bevarande ---
# (ProGuard ignorerar detta direktiv)
-keep,allowobfuscation class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator CREATOR;
}

Efter konfiguration, utför bygget: ./gradlew assembleRelease. Kontrollera att filerna har dykt upp i build/outputs/mapping/release/: mapping.txt (motsvarande ursprungliga och obfuskerade namn), seeds.txt (klasser bevarade av -keep-regler), usage.txt (klasser borttagna vid minifiering). APK-storleken efter obfuskering bör minska med 20–50% beroende på antalet anslutna bibliotek.

Vanliga frågor

Hur skiljer sig R8 från ProGuard?

R8 — efterträdare till ProGuard, utvecklad av Google. R8 utför obfuskering, minifiering och optimering i en enda passage, arbetar 2–3 gånger snabbare än ProGuard och är direkt integrerad i Android Gradle Plugin. ProGuard använder fyra separata faser och kräver extern körning. Från AGP 7.0 används inte ProGuard — som standard fungerar R8.

Måste jag skriva ProGuard rules när jag använder R8?

Ja, R8 använder samma ProGuard rules (.pro-filer). Direktiven -keep, -keepclassmembers, -keepattributes, -assumenosideeffects fungerar identiskt. Basreglerna kommer från proguard-android-optimize.txt från Android SDK och de specifika för bibliotek (Retrofit, Room, Gson) läggs till i projektets proguard-rules.pro. Utan dessa regler kan R8 ta bort klasser som krävs för att biblioteken ska fungera via reflection.

Hur aktiverar jag R8 i ett Android-projekt?

R8 är som standard aktiverat i Android Gradle Plugin från AGP 3.4. För att aktivera minifiering, ställ in isMinifyEnabled = true i blocket release buildType i filen build.gradle.kts. Den extra flaggan isShrinkResources = true aktiverar borttagning av oanvända resurser. I gradle.properties kan R8 tvångsinaktiveras via android.enableR8=false, men detta rekommenderas inte — R8 är snabbare och stabilare.

Vad är kodobfuskering i Android?

Obfuskering — omdöpning av klasser, metoder och fält till korta meningslösa namn (a, b, c). Klassen com.example.app.auth.LoginManager blir a.a.a, metoden authenticateUser blir a. Detta försvårar reverse engineering av appen men påverkar inte körningslogiken. ProGuard och R8 byter bara namn på element som inte skyddas av -keep-regler. Mapping-filen bevarar motsvarande ursprungliga och obfuskerade namn för avkodning av crashloggar.

Hur felsöker jag en crashlog från en obfuskerad app?

För avkodning av stack trace används verktyget retrace (ingår i ProGuard/R8 SDK). Kommando: retrace mapping.txt crash-stacktrace.txt. Mapping-filen finns i build/outputs/mapping/release/mapping.txt. Google Play Console stöder också uppladdning av mapping.txt vid publicering av AAB — crashloggar avkodas automatiskt i konsolen. Utan mapping-fil kommer stack trace endast att innehålla obfuskerade namn a.b.c(), vilket är oanvändbart för felsökning.

Sammanfattning

  • ProGuard — klassiskt verktyg för obfuskering och optimering av Java-bytekod, bestående av fyra på varandra följande faser
  • R8 — modern efterträdare från Google, inbyggd i AGP, utför alla faser i en enda passage med 2–3 gånger högre prestanda
  • Obfuskering byter namn på klasser, metoder och fält till korta namn, försvårar reverse engineering och skyddar appens kommersiella logik
  • Minifiering tar bort oanvänd kod och resurser, minskar APK-storleken med 20–50% i typiska projekt
  • ProGuard rules (.pro-filer) styr obfuskeringsbeteendet — direktiven -keep, -keepclassmembers, -assumenosideeffects specificerar vilka element som bevaras, tas bort eller byter namn
  • Mapping-fil (mapping.txt) — kritisk byggartefakt för avkodning av crashloggar från release-byggen via retrace
  • Testning av release-bygget på en verklig enhet är obligatorisk — obfuskeringsproblem uppträder endast vid körning och kräver tillägg av saknade -keep-regler

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också