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
| Capability | R8 | Shield |
|---|---|---|
| Code shrinking (unused code removal) | Yes (recommended) | Yes |
| Resource shrinking | Yes (recommended) | Yes |
| Name obfuscation | Basic (a, b, c) | Advanced (multiple modes, mapping) |
| String encryption | No | Yes |
| Constant mutation | No | Yes |
| Control flow obfuscation | No | Yes |
| Anti-debug | No | Yes |
| Anti-tamper | No | Yes |
| Reference proxy | No | Yes |
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:
| Directive | Behavior in Shield |
|---|---|
-keep | Preserves classes and members from all protections |
-keepclassmembers | Preserves class members but allows the class itself to be renamed |
-keepclasseswithmembers | Keeps classes only when the specified members are present |
-keepnames | Prevents renaming but allows other protections to apply |
-keepclassmembernames | Prevents renaming of members only |
-dontobfuscate | Disables name obfuscation globally |
-keepattributes | Preserves 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:
| Annotation | Source |
|---|---|
@androidx.annotation.Keep | AndroidX |
@android.support.annotation.Keep | Android Support Library |
@com.bytehide.shield.annotations.Keep | Shield (native) |
@ProguardKeep | Custom ProGuard convention |
@DoNotObfuscate | Common convention |
@DoNotRename | Common convention |
@com.fasterxml.jackson.annotation.JsonProperty | Jackson serialization |
@com.google.gson.annotations.SerializedName | Gson 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:
com.example.MyClass -> a.b:
int secretValue -> a
void processData() -> bcom.example.MyClass -> a.b:
int secretValue -> a
void processData() -> bThis 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:
- Keep your
proguard-rules.profile — Shield respects all existing keep rules. - Keep your existing annotations —
@androidx.annotation.Keepand other standard annotations work with Shield. - Add Shield protections — Enable the protections you need in the
shield { }block. They layer on top of your existing configuration. - No rule rewriting required — Your ProGuard rules work as-is. You can optionally add Shield-specific annotations (
@Exclude,@DoNotObfuscate) for finer control later.
Recommended Configuration
When R8 is Enabled (Most Projects)
If your project uses minifyEnabled true (which enables R8), disable Shield's name obfuscation to avoid conflicts:
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
}
}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:
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
}
}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:
# ByteHide Shield Runtime
-keep class com.bytehide.runtime.** { *; }
# Preserve Shield annotations
-keep @interface com.bytehide.shield.annotations.** { *; }
-keep @com.bytehide.shield.annotations.Keep class * { *; }# 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:
- Compilation —
javac/kotlinccompile source to.classfiles - Shield — Applies protections (string encryption, control flow, etc.)
- R8 — Shrinks unused code, optimizes, and applies name obfuscation
- 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:
-keep class com.yourpackage.models.** { *; }-keep class com.yourpackage.models.** { *; }Related
- Gradle DSL Reference — Full configuration options
- Excluded Packages — Fine-tune which packages Shield processes
- Annotations — Exclude individual classes or methods from protection