ProGuard/R8: podstata, obfuskace a ochrana aplikací pro Android

Autor: IT Sectr Publikováno: 2026-02-14 Doba čtení: 8 min

ProGuard a R8 — nástroje pro obfuskaci, minifikaci a optimalizaci pro Android aplikace. ProGuard, vytvořený v roce 2002, byl po dlouhou dobu de facto standardem pro ochranu Java kódu. R8 — jeho nástupce, vyvinutý společností Google a integrovaný do Android Gradle Plugin od AGP 3.4. Oba nástroje zmenšují velikost APK, odstraňují mrtvý kód a ztěžují zpětné inženýrství. Podle Android Developers, R8 provádí sestavení 2–3krát rychleji než ProGuard při srovnatelné kvalitě obfuskace.

Hlavní body

  • ProGuard — nástroj pro obfuskaci a optimalizaci Java bytekódu, standard pro Android od 2000. let
  • R8 — nástupce ProGuard od Google, integrovaný v AGP, provádí obfuskaci, minifikaci a optimalizaci v jednom průchodu
  • Obfuskace přejmenovává třídy a metody na krátké názvy, čímž ztěžuje zpětné inženýrství aplikace
  • Minifikace odstraňuje nepoužívané třídy, metody a pole, čímž zmenšuje velikost výsledného APK/AAB
  • ProGuard rules (soubory .pro) řídí, které části kódu se uchovávají, obfuskovávají nebo odstraňují

Co je ProGuard?

ProGuard — je open-source nástroj (Apache 2.0) pro obfuskaci, minifikaci, optimalizaci a předběžné ověření Java bytekódu. Vyvinutý Ericem Lafourgem v roce 2002 v rámci projektu SourceForge. ProGuard přijímá na vstupu zkompilované Java třídy (.class) nebo JAR archivy a vytváří zpracované třídy stejného formátu, ale menší velikosti s přejmenovanými prvky.

ProGuard byl po dlouhou dobu jediným standardem pro ochranu Android aplikací před zpětným inženýrstvím. Google oficiálně doporučoval jeho použití v Android SDK a dodával výchozí konfiguraci v souboru proguard-android-optimize.txt v SDK tools. ProGuard fungoval jako samostatný nástroj spouštěný po kompilaci Java kódu do bytekódu a před zabalením do DEX.

Architektura ProGuard

ProGuard se skládá ze čtyř po sobě jdoucích fází: shrink (odstranění nepoužívaných tříd), optimize (optimalizace bytekódu — inlining, odstranění mrtvého kódu), obfuscate (přejmenování tříd, metod a polí na krátké názvy), preverify (kontrola kompatibility s JVM). Každá fáze je řízena samostatnými pravidly z konfiguračních souborů.

Ve fázi obfuskace ProGuard generuje mapping soubor (mapping.txt), který mapuje původní názvy na obfuskované. Tento soubor je kritický pro dekódování crash logů z release sestavení pomocí nástroje retrace. Bez mapping souboru se stack trace změní na sadu písmen a(), b(), c() bez možnosti obnovení původního kontextu.

Fáze ProGuardÚčelVýsledek
ShrinkAnalýza grafu volání a odstranění mrtvého kóduSnížení počtu tříd v APK
OptimizeInlining metod, odstranění nepoužívaných parametrůZrychlení provádění kódu
ObfuscatePřejmenování tříd, polí a metodOchrana proti zpětnému inženýrství
PreverifyPřidání StackMap atributů pro JVMKompatibilita s Java 6+

Co je R8?

R8 — je nástroj pro obfuskaci a minifikaci nové generace od Google, poprvé představený v Android Studio 3.3 (listopad 2018) a standardem v AGP 3.4 (srpen 2019). Na rozdíl od ProGuard je R8 součástí kompilátoru D8/R8, který převádí Java bytekód do formátu DEX. R8 provádí všechny fáze — obfuskaci, minifikaci i optimalizaci — v jednom průchodu, bez předávání mezisouborů mezi nástroji.

Google vyvinul R8 se dvěma cíli: urychlit sestavení (ProGuard fungoval jako externí nástroj) a zajistit bezproblémovou integraci s moderním Android stackem (Desugar, Core Library Desugaring, D8). R8 je napsán v Kotlin a Java a je součástí repozitáře R8/Desugar v AOSP (Android Open Source Project).

Důležitá výhoda R8 — plná zpětná kompatibilita s ProGuard rules. Stávající .pro soubory fungují beze změn. R8 dokonce podporuje specifické ProGuard direktivy, včetně -whyareyoukeeping, -printconfiguration a -printmapping. To znamená, že přechod z ProGuard na R8 probíhá transparentně: stačí aktualizovat AGP.

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

            proguardFiles(
                // Základní konfigurace z Android SDK
                getDefaultProguardFile("proguard-android-optimize.txt"),
                // Vlastní pravidla projektu
                "proguard-rules.pro"
            )
        }
    }
}

Kód demonstruje standardní konfiguraci release sestavení. Příznak isMinifyEnabled = true aktivuje R8 pro obfuskaci a optimalizaci. isShrinkResources = true navíc odstraňuje nepoužívané zdroje. getDefaultProguardFile načítá základní pravidla ze SDK a proguard-rules.pro obsahuje nastavení specifická pro projekt.

Obfuskace kódu v Android

Obfuskace — je proces převodu zdrojového kódu do formy, kterou je obtížné analyzovat pro člověka, ale která zachovává plnou funkčnost. V kontextu Android obfuskace znamená přejmenování tříd, metod a polí na krátké, významu zbavené názvy: com.example.app.auth.LoginManager se změní na a.a.a, metoda authenticateUser na a, pole userToken na b.

Proč je obfuskace potřebná

Soubory APK Android jsou archivy, které lze otevřít libovolným archivátorem (ZIP, 7z, WinRAR). Bez obfuskace získá útočník úplnou mapu aplikace: názvy balíčků, tříd, metod a polí. Nástroje jako jadx nebo Bytecode Viewer obnoví téměř původní Java kód z DEX souborů během několika sekund. Obfuskace nečiní kód nezranitelným, ale výrazně zvyšuje práh vstupu: místo smysluplných názvů čtenář vidí a(), b(), c().

Typické cíle obfuskace: ochrana komerční logiky (algoritmy, výpočetní vzorce), ztížení krádeže API klíčů a tokenů, prevence nahrazování tříd pomocí reflection, ochrana proti patchování a modifikaci APK (repackage attack). V praxi 70% úkolů řeší právě přejmenování — kvůli tomu se spouští ProGuard / R8.

Příklad pravidel ProGuard

Níže je typický soubor proguard-rules.pro pro Android projekt s Retrofit, Gson a Parcelable. Pravidla -keep uchovávají třídy a metody nezbytné pro fungování knihoven pomocí reflection. Bez těchto pravidel R8 odstraní nebo přejmenuje třídy, ke kterým knihovna přistupuje podle názvu řetězce.

pro
# =====================
# Retrofit — uchování rozhraní
# =====================
-keep,allowobfuscation,allowshrinking interface retrofit2.** { *; }
-keepattributes Signature, Exceptions

# =====================
# Gson — serializace 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 — odstranění logů z 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 třídy — uchování konstruktorů
# =====================
-keepclassmembers class * {
    @kotlin.Metadata <fields>;
}

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

Každá direktiva v .pro souboru řeší konkrétní úkol. -keep zabraňuje odstranění nebo přejmenování celé třídy. -keepclassmembers chrání pouze členy třídy (pole a metody), ale umožňuje odstranění samotné třídy, pokud se nepoužívá. -assumenosideeffects říká R8, že volání metody nemá vedlejší účinky a může být bezpečně odstraněno. Direktiva -keepattributes uchovává metadata v bytekódu — anotace, signatury, výjimky.

Pravidlo -keep,allowobfuscation,allowshrinking pro Retrofit umožňuje R8 přejmenovávat rozhraní, ale ne je odstraňovat. To je nezbytné, protože Retrofit přistupuje k rozhraním přes dynamický proxy (java.lang.reflect.Proxy) a odstranění by vedlo k ClassNotFoundException za běhu. Podobně Gson používá reflection pro přístup k polím s anotací @SerializedName — bez -keepclassmembers budou pole odstraněna jako nepoužívaná.

Minifikace a ShrinkResources

Minifikace (shrinking) — proces odstraňování nepoužívaného kódu a zdrojů z konečného sestavení. ProGuard a R8 analyzují graf volání, počínaje vstupními body (Activity, Service, BroadcastReceiver), a odstraňují třídy a metody, ke kterým nelze dospět řetězcem volání. ShrinkResources — dodatečná fáze, která odstraňuje nepoužívané zdroje z res/ (layout, drawable, string, color).

Minifikace přináší největší zisk ve velkých projektech s knihovnami. Typický obrázek: projekt používá 10% kódu z připojené knihovny (např. Google Play Services). Bez minifikace se veškerý kód knihovny dostane do APK. S minifikací R8 odstraňuje 70–90% kódu knihoven a ponechává pouze skutečně používané třídy a metody. To přímo ovlivňuje velikost APK, dobu načítání a spotřebu paměti.

ShrinkResources v akci

Mechanismus ShrinkResources pracuje ve spojení s minifikací kódu. Poté, co R8 určí, které třídy se používají, zmenšování zdrojů analyzuje odkazy na zdroje z kódu: R.layout.main, R.drawable.icon, getString(R.string.title). Všechny zdroje, na které není přímý nebo nepřímý odkaz, jsou odstraněny z konečného APK nebo AAB. K tomu se používá soubor zdrojů resources.arsc a složky res/.

Důležitá nuance: zdroje mohou být volány prostřednictvím getIdentifier() nebo Resources.getResourceName() podle názvu řetězce, čímž se obchází třída R. V takových případech R8 nevidí přímé spojení a může odstranit zdroj, který je ve skutečnosti používán. K ochraně takových zdrojů existuje direktiva -keep class **.R$* { *; } — uchovává všechny identifikátory třídy R.

xml
<!-- Příklad: zdroj, který se používá pouze přes getIdentifier() -->
<string name="dynamic_title_welcome">Vítejte</string>
<string name="dynamic_title_share">Sdílet</string>

<!-- Kotlin kód přistupující přes řetězec -->
<!-- val title = getString(resources.getIdentifier( -->
<!--     \"dynamic_title_${type}\", \"string\", packageName)) -->

V tomto případě R8 nevidí statický odkaz na dynamic_title_welcome ve třídě R, protože přístup probíhá přes getIdentifier s dynamickým názvem. Pro uchování takových zdrojů je třeba přidat do proguard-rules.pro direktivu -keepclassmembers class **.R$string { *; } — zakazuje odstranění libovolných polí ze všech tříd R$string.

DirektivaÚčelPříklad
-keepUchovává třídu a všechny její členy-keep class com.example.api.** { *; }
-keepclassmembersUchovává pouze členy třídy-keepclassmembers class * { @SerializedName <fields>; }
-keepattributesUchovává metadata bytekódu-keepattributes *Annotation*, Signature
-assumenosideeffectsOdstraňuje volání bez vedlejších účinků-assumenosideeffects class Log { d(...); }
-dontwarnPotlačuje varování-dontwarn com.example.legacy.**

R8 vs ProGuard: klíčové rozdíly

Přestože je R8 nástupcem ProGuard, existují mezi nástroji zásadní rozdíly v architektuře, výkonu a chování. Google oficiálně ukončil podporu ProGuard v Android Gradle Plugin od AGP 7.0, avšak ProGuard se nadále používá v projektech, kde je vyžadováno specifické chování optimalizace nedostupné v R8.

Srovnávací tabulka

CharakteristikaProGuardR8
VývojářGuardSquare (Eric Lafourge)Google
Rok vydání20022018 (stabilní 2019)
Architektura4 samostatné fáze (shrink → optimize → obfuscate → preverify)Jeden průchod: shrink + optimize + obfuscate současně
Integrace do AGPExterní nástroj, spouštěný po javacIntegrován do D8 DEX kompilátoru
Rychlost sestavení2–3krát pomalejšíRychlejší díky jednomu průchodu a nativní integraci
Podpora KotlinOmezená (problémy s inline, lambdas, coroutines)Plná: coroutines, inline funkce, data class
Mapping soubormapping.txt (kompatibilní s retrace)mapping.txt (stejný formát)
Přizpůsobení optimalizace60+ možností -optimizationpasses, -optimizationsOmezené: většina optimalizací je ve výchozím nastavení zapnuta
Stav podporyNahrazen R8 (AGP 7.0+ nepoužívá)Aktivní vývoj, součást AOSP

Kdy může R8 rozbít sestavení

R8 agresivněji než ProGuard odstraňuje kód, který považuje za mrtvý. To vede k situacím, kdy debug sestavení funguje, ale release padá s ClassNotFoundException nebo NoSuchMethodException. Typické případy: knihovny používající reflection podle názvu třídy (Gson, Moshi, Retrofit, Room, Dagger); volání ServiceLoader nebo java.util.ServiceLoader; dynamické proxy (java.lang.reflect.Proxy); nativní metody (JNI). Řešení — přidejte -keep pro všechny třídy, které jsou volány pomocí reflection.

pro
# Typické problémy reflection — R8 nevidí statické propojení

# Room — uchování DAO a migrací
-keep class * extends androidx.room.RoomDatabase { *; }
-keep class *.DatabaseMigrations { *; }

# Dagger / Hilt — uchování komponent
-keep class * extends dagger.hilt.android.components.** { *; }

# JNI — nepřejmenováváme nativní metody
-keepclasseswithmembernames class * {
    native <methods>;
}

# Data Binding — uchování Binding tříd
-keep class *.databinding.** { *; }

Pokud po přidání pravidel sestavení stále padá, použijte příznak -printconfiguration full-config.txt v proguard-rules.pro. R8 vygeneruje úplný konfigurační soubor, který ukazuje, která pravidla byla použita a které třídy jsou uchovávány. Užitečná je také direktiva -whyareyoukeeping class com.example.MyClass — vypisuje důvod, proč se R8 rozhodl danou třídu uchovat.

Nastavení ProGuard rules

Správné nastavení ProGuard rules — klíč ke stabilnímu provozu obfuskace bez chyb za běhu. Níže je postup krok za krokem pro nový projekt nebo pro projekt, ve kterém obfuskace způsobuje chyby.

Krok 1: Základní konfigurace

Začněte připojením standardního souboru Android SDK — proguard-android-optimize.txt. Obsahuje pravidla pro základní Android komponenty: Activity, Service, BroadcastReceiver, ContentProvider, View, Fragment. Tento soubor se nachází ve složce SDK: $ANDROID_HOME/tools/proguard/proguard-android-optimize.txt. Pokud používáte AGP, getDefaultProguardFile jej načte automaticky.

Krok 2: Knihovny

Každá populární knihovna má doporučená ProGuard pravidla. Retrofit, OkHttp, Glide, Fresco, Coil, Room, Dagger/Hilt, Kotlin Coroutines — všechny vyžadují specifická -keep pravidla. Obvykle jsou pravidla zahrnuta v AAR knihovně a připojují se automaticky prostřednictvím consumer guard rules. Zkontrolujte, zda knihovna poskytuje soubor proguard.txt uvnitř AAR — to je známka toho, že pravidla jsou již zohledněna.

Krok 3: Testování release sestavení

Před publikováním nezbytně otestujte release sestavení na skutečném zařízení nebo emulátoru. Problémy obfuskace se projevují pouze za běhu. Zkontrolujte: autentizaci (přihlášení/registraci), načítání dat ze sítě, navigaci mezi obrazovkami, kameru a galerii, push notifikace, Deeplinky, WebView. Každý pád v release sestavení je třeba dekódovat pomocí retrace s mapping souborem a přidat chybějící -keep pravidla.

Krok 4: Mapping soubor a CI

Mapping soubor je generován v build/outputs/mapping/release/mapping.txt. Tento soubor je povinné uchovat: bez něj nelze dekódovat crash logy z Google Play Console. Zahrňte mapping.txt do systému správy verzí nebo jej nahrajte jako CI artefakt. Google Play Console automaticky přijímá mapping soubor při nahrávání AAB s aktivovaným uploading mapping.txt.

Níže je úplný workflow nastavení obfuskace v souboru proguard-rules.pro s komentáři pro každou skupinu pravidel.

pro
# ===========================================
# proguard-rules.pro — úplný příklad
# ===========================================

# --- Obecná nastavení ---
-keepattributes *Annotation*, Signature, Exceptions, InnerClasses, EnclosingMethod
-dontpreverify

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

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

# --- Pouze R8: vynucené uchování ---
# (ProGuard tuto direktivu ignoruje)
-keep,allowobfuscation class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator CREATOR;
}

Po nastavení proveďte sestavení: ./gradlew assembleRelease. Zkontrolujte, zda se v build/outputs/mapping/release/ objevily soubory: mapping.txt (odpovídající původních a obfuskovaných názvů), seeds.txt (třídy uchované pravidly -keep), usage.txt (třídy odstraněné při minifikaci). Velikost APK po obfuskaci by se měla snížit o 20–50% v závislosti na počtu připojených knihoven.

Často kladené otázky

Čím se liší R8 od ProGuard?

R8 — nástupce ProGuard, vyvinutý společností Google. R8 provádí obfuskaci, minifikaci a optimalizaci v jednom průchodu, pracuje 2–3krát rychleji než ProGuard a je integrován přímo do Android Gradle Plugin. ProGuard používá čtyři samostatné fáze a vyžaduje externí spuštění. Od AGP 7.0 se ProGuard nepoužívá — ve výchozím nastavení pracuje R8.

Je třeba psát ProGuard rules při použití R8?

Ano, R8 používá stejná ProGuard rules (soubory .pro). Direktivy -keep, -keepclassmembers, -keepattributes, -assumenosideeffects fungují identicky. Základní pravidla pocházejí z proguard-android-optimize.txt z Android SDK a specifická pro knihovny (Retrofit, Room, Gson) se přidávají do proguard-rules.pro projektu. Bez těchto pravidel může R8 odstranit třídy nezbytné pro fungování knihoven prostřednictvím reflection.

Jak zapnout R8 v Android projektu?

R8 je ve výchozím nastavení zapnut v Android Gradle Plugin od AGP 3.4. Pro aktivaci minifikace nastavte isMinifyEnabled = true v bloku release buildType souboru build.gradle.kts. Další příznak isShrinkResources = true zapíná odstraňování nepoužívaných zdrojů. V gradle.properties lze R8 vynuceně vypnout pomocí android.enableR8=false, ale to se nedoporučuje — R8 je rychlejší a stabilnější.

Co je obfuskace kódu v Android?

Obfuskace — přejmenování tříd, metod a polí na krátké bezvýznamné názvy (a, b, c). Třída com.example.app.auth.LoginManager se změní na a.a.a, metoda authenticateUser na a. To ztěžuje zpětné inženýrství aplikace, ale neovlivňuje logiku provádění. ProGuard a R8 přejmenovávají pouze prvky, které nejsou chráněny pravidly -keep. Mapping soubor uchovává odpovídající původní a obfuskované názvy pro dekódování crash logů.

Jak odladit crash-log z obfuskované aplikace?

Pro dekódování stack trace se používá nástroj retrace (součást ProGuard/R8 SDK). Příkaz: retrace mapping.txt crash-stacktrace.txt. Mapping soubor se nachází v build/outputs/mapping/release/mapping.txt. Google Play Console také podporuje nahrávání mapping.txt při publikování AAB — crash logy jsou automaticky dekódovány v konzoli. Bez mapping souboru bude stack trace obsahovat pouze obfuskované názvy a.b.c(), což je k ladění nepoužitelné.

Shrnutí

  • ProGuard — klasický nástroj pro obfuskaci a optimalizaci Java bytekódu, sestávající ze čtyř po sobě jdoucích fází
  • R8 — moderní nástupce od Google, integrovaný v AGP, provádějící všechny fáze v jednom průchodu s 2–3krát vyšším výkonem
  • Obfuskace přejmenovává třídy, metody a pole na krátké názvy, ztěžuje zpětné inženýrství a chrání komerční logiku aplikace
  • Minifikace odstraňuje nepoužívaný kód a zdroje, snižuje velikost APK o 20–50% v typických projektech
  • ProGuard rules (soubory .pro) řídí chování obfuskace — direktivy -keep, -keepclassmembers, -assumenosideeffects určují, které prvky se uchovávají, odstraňují nebo přejmenovávají
  • Mapping soubor (mapping.txt) — kritický artefakt sestavení pro dekódování crash logů z release sestavení pomocí retrace
  • Testování release sestavení na skutečném zařízení je povinné — problémy obfuskace se projevují pouze za běhu a vyžadují přidání chybějících -keep pravidel

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také