/

R8 & ProGuard Compatibility

Shield is fully backward-compatible with ProGuard configuration rules, annotations, and mapping file format. It also works alongside R8 (Android's built-in code shrinker), but their responsibilities should be clearly separated to avoid conflicts.


How Shield and R8 Differ

CapabilityR8Shield
Code shrinking (unused code removal)Yes (recommended)Yes
Resource shrinkingYes (recommended)Yes
Name obfuscationBasic (a, b, c)Advanced (multiple modes, mapping)
String encryptionNoYes
Constant mutationNoYes
Control flow obfuscationNoYes
Anti-debugNoYes
Anti-tamperNoYes
Reference proxyNoYes

R8 focuses on reducing APK size by removing unused code and resources. Shield focuses on protecting code against reverse engineering and analysis. They complement each other.


ProGuard Backward Compatibility

Shield is fully backward-compatible with ProGuard configuration rules. If your project already uses a proguard-rules.pro file, Shield recognizes and respects those rules automatically — no migration required.

Supported ProGuard Directives

Shield's configuration parser supports the standard ProGuard keep-rule directives:

DirectiveBehavior in Shield
-keepPreserves classes and members from all protections
-keepclassmembersPreserves class members but allows the class itself to be renamed
-keepclasseswithmembersKeeps classes only when the specified members are present
-keepnamesPrevents renaming but allows other protections to apply
-keepclassmembernamesPrevents renaming of members only
-dontobfuscateDisables name obfuscation globally
-keepattributesPreserves specified bytecode attributes

All ProGuard wildcard patterns (*, **, ***, <init>, <methods>, <fields>) work as expected.

Recognized Annotations

Shield automatically detects and respects keep-related annotations from multiple sources. Any class or member annotated with these is automatically excluded from protection:

AnnotationSource
@androidx.annotation.KeepAndroidX
@android.support.annotation.KeepAndroid Support Library
@com.bytehide.shield.annotations.KeepShield (native)
@ProguardKeepCustom ProGuard convention
@DoNotObfuscateCommon convention
@DoNotRenameCommon convention
@com.fasterxml.jackson.annotation.JsonPropertyJackson serialization
@com.google.gson.annotations.SerializedNameGson serialization

This means projects that already use @androidx.annotation.Keep or any other standard keep annotation do not need to adopt Shield-specific annotations — Shield respects them automatically.

ProGuard Mapping Format

Shield reads and writes mapping files in the standard ProGuard mapping format:

TEXT
com.example.MyClass -> a.b:
    int secretValue -> a
    void processData() -> b

This means mapping files are compatible with tools that expect ProGuard mapping format, such as Firebase Crashlytics, Bugsnag, and Sentry. See Mapping Files for more details.

Migrating from ProGuard to Shield

If you are migrating from a ProGuard-only setup:

  1. Keep your proguard-rules.pro file — Shield respects all existing keep rules.
  2. Keep your existing annotations@androidx.annotation.Keep and other standard annotations work with Shield.
  3. Add Shield protections — Enable the protections you need in the shield { } block. They layer on top of your existing configuration.
  4. No rule rewriting required — Your ProGuard rules work as-is. You can optionally add Shield-specific annotations (@Exclude, @DoNotObfuscate) for finer control later.

When R8 is Enabled (Most Projects)

If your project uses minifyEnabled true (which enables R8), disable Shield's name obfuscation to avoid conflicts:

Groovy
android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

shield {
    protections {
        nameObfuscation = false  // Let R8 handle renaming
        stringEncryption = true
        constantMutation = true
        controlFlowObfuscation = true
        debugRemoval = true
        antiDebug = true
        referenceProxy = true
        antiTamper = true
    }
}

This gives you R8's shrinking plus Shield's advanced protections that R8 does not provide.

When R8 is Disabled

If you disable R8 (minifyEnabled false), you can enable all Shield protections including name obfuscation:

Groovy
android {
    buildTypes {
        release {
            minifyEnabled false
        }
    }
}

shield {
    protections {
        nameObfuscation = true  // Shield handles renaming
        stringEncryption = true
        constantMutation = true
        controlFlowObfuscation = true
        debugRemoval = true
        antiDebug = true
        referenceProxy = true
        resourceProtection = true
        antiTamper = true
    }
}

Note that without R8, your APK will be larger because unused code is not removed.


ProGuard Rules for Shield

When R8 is enabled, add these rules to your proguard-rules.pro to ensure Shield's runtime classes are preserved:

ProGuard
# ByteHide Shield Runtime
-keep class com.bytehide.runtime.** { *; }

# Preserve Shield annotations
-keep @interface com.bytehide.shield.annotations.** { *; }
-keep @com.bytehide.shield.annotations.Keep class * { *; }

These rules prevent R8 from removing or renaming Shield's runtime library, which is required for string decryption and anti-debug checks.


Processing Order

When both R8 and Shield are enabled, they process the bytecode in sequence:

  1. Compilationjavac / kotlinc compile source to .class files
  2. Shield — Applies protections (string encryption, control flow, etc.)
  3. R8 — Shrinks unused code, optimizes, and applies name obfuscation
  4. Packaging — DEX conversion and APK/AAB assembly

Shield processes the bytecode before R8, so Shield's protections are applied to the full codebase. R8 then shrinks the already-protected code.


Common Issues

Duplicate Name Obfuscation

If both Shield and R8 perform name obfuscation, class and method references can break. Symptom: ClassNotFoundException or NoSuchMethodError at runtime. Solution: set nameObfuscation = false in Shield when R8 is enabled.

Missing Runtime Classes

If R8 removes Shield's StringDecryptor class, encrypted strings cannot be decrypted at runtime. Symptom: ClassNotFoundException: com.bytehide.runtime.StringDecryptor. Solution: add the keep rule for com.bytehide.runtime.**.

Kotlin Reflection

Kotlin reflection relies on metadata that can be affected by obfuscation. If you use ::class, KClass, or KFunction, apply @DoNotObfuscate to the affected classes or add a ProGuard rule:

ProGuard
-keep class com.yourpackage.models.** { *; }

Previous
CI/CD Integration