Annotations
Shield provides three annotations for fine-grained control over which protections apply to individual classes, methods, fields, and constructors.
Available Annotations
| Annotation | Effect | Use Case |
|---|---|---|
@Keep | Excludes from all protections | Reflection, JNI, serialization |
@DoNotObfuscate | Prevents name obfuscation only | Elements that must keep their name but can be otherwise protected |
@Exclude | Excludes from specific protections | Selective control per protection type |
All three annotations are in the com.bytehide.shield.annotations package and can be applied to types, methods, fields, and constructors.
@Keep
Prevents all protections from applying to the annotated element. The element retains its original name, strings are not encrypted, control flow is not obfuscated, and constants are not mutated.
Java
import com.bytehide.shield.annotations.Keep;
@Keep
public class ReflectionTarget {
public String name;
public int value;
public void process() {
// Nothing in this class is modified by Shield
}
}import com.bytehide.shield.annotations.Keep;
@Keep
public class ReflectionTarget {
public String name;
public int value;
public void process() {
// Nothing in this class is modified by Shield
}
}Kotlin
import com.bytehide.shield.annotations.Keep
@Keep
data class ApiResponse(
val status: String,
val data: Map<String, Any>
)import com.bytehide.shield.annotations.Keep
@Keep
data class ApiResponse(
val status: String,
val data: Map<String, Any>
)When to Use @Keep
- Classes instantiated via reflection (
Class.forName()) - JNI native method declarations
- Classes serialized with Gson, Jackson, or Moshi (where field names must match JSON keys)
- Classes referenced by name in XML configurations
- Entry points registered in
AndroidManifest.xml
@DoNotObfuscate
Prevents name obfuscation only. All other protections (string encryption, control flow, constant mutation, etc.) still apply. The class, method, or field retains its original name.
Java
import com.bytehide.shield.annotations.DoNotObfuscate;
@DoNotObfuscate
public class EventNames {
public static final String LOGIN = "user_login"; // String IS encrypted
public static final String PURCHASE = "purchase"; // String IS encrypted
// But class name "EventNames" and field names are preserved
}import com.bytehide.shield.annotations.DoNotObfuscate;
@DoNotObfuscate
public class EventNames {
public static final String LOGIN = "user_login"; // String IS encrypted
public static final String PURCHASE = "purchase"; // String IS encrypted
// But class name "EventNames" and field names are preserved
}Kotlin
import com.bytehide.shield.annotations.DoNotObfuscate
@DoNotObfuscate
class AnalyticsTracker {
fun trackEvent(name: String) {
// Method name "trackEvent" preserved
// But method body still gets control flow obfuscation
}
}import com.bytehide.shield.annotations.DoNotObfuscate
@DoNotObfuscate
class AnalyticsTracker {
fun trackEvent(name: String) {
// Method name "trackEvent" preserved
// But method body still gets control flow obfuscation
}
}When to Use @DoNotObfuscate
- Classes used in logging where the class name appears in output
- Kotlin data classes used with reflection but where you still want string encryption
- Library modules where public API names must be stable
@Exclude
Excludes from specific protections. Accepts an array of protection names. If the array is empty, behaves like @Keep (excludes from all).
Protection Names
| Name | Protection |
|---|---|
"NameObfuscation" | Name obfuscation (renaming) |
"StringEncryption" | String literal encryption |
"ControlFlowMatrix" | Control flow obfuscation |
"ConstantMutation" | Constant value mutation |
"DebugInfoRemoval" | Debug metadata removal |
Java
import com.bytehide.shield.annotations.Exclude;
// Exclude from string encryption only
@Exclude(protections = {"StringEncryption"})
public void logMessage(String message) {
Log.d("MyApp", message);
}
// Exclude from multiple protections
@Exclude(protections = {"StringEncryption", "ControlFlowMatrix"})
public class DebugHelper {
public void dumpState() {
// Strings readable, control flow preserved
// But names still obfuscated and constants still mutated
}
}
// Empty array = exclude from all (equivalent to @Keep)
@Exclude
public native void nativeMethod();import com.bytehide.shield.annotations.Exclude;
// Exclude from string encryption only
@Exclude(protections = {"StringEncryption"})
public void logMessage(String message) {
Log.d("MyApp", message);
}
// Exclude from multiple protections
@Exclude(protections = {"StringEncryption", "ControlFlowMatrix"})
public class DebugHelper {
public void dumpState() {
// Strings readable, control flow preserved
// But names still obfuscated and constants still mutated
}
}
// Empty array = exclude from all (equivalent to @Keep)
@Exclude
public native void nativeMethod();Kotlin
import com.bytehide.shield.annotations.Exclude
@Exclude(protections = ["StringEncryption", "ConstantMutation"])
fun buildConnectionString(): String {
val host = "db.internal.example.com"
val port = 5432
return "$host:$port"
// Host string and port constant are preserved as-is
// But name can still be obfuscated
}import com.bytehide.shield.annotations.Exclude
@Exclude(protections = ["StringEncryption", "ConstantMutation"])
fun buildConnectionString(): String {
val host = "db.internal.example.com"
val port = 5432
return "$host:$port"
// Host string and port constant are preserved as-is
// But name can still be obfuscated
}Annotation Targets
All three annotations support the same targets:
| Target | Example |
|---|---|
TYPE | Class, interface, enum |
METHOD | Instance and static methods |
FIELD | Instance and static fields |
CONSTRUCTOR | Class constructors |
When applied to a type, the annotation affects all members of that type.
Backward Compatibility with Other Annotations
Shield also recognizes standard keep annotations from other frameworks. If your codebase already uses any of these, Shield respects them automatically — the annotated elements are excluded from protection without any changes:
| Annotation | Source |
|---|---|
@androidx.annotation.Keep | AndroidX |
@android.support.annotation.Keep | Android Support Library |
@ProguardKeep | Custom ProGuard convention |
@DoNotRename | Common convention |
Serialization framework annotations are also recognized. Classes and fields annotated with @JsonProperty (Jackson), @SerializedName (Gson), or @Entity / @Column (JPA) are automatically preserved.
This means you do not need to replace existing annotations with Shield-specific ones. You can adopt @Keep, @DoNotObfuscate, and @Exclude from Shield selectively for finer control, while your existing annotations continue to work.
Dependency
The annotations are in the shield-java-annotations artifact:
dependencies {
compileOnly 'com.bytehide:shield-java-annotations:1.0.0'
}dependencies {
compileOnly 'com.bytehide:shield-java-annotations:1.0.0'
}Using compileOnly ensures the annotation classes are available during compilation but not included in the final APK (they have @Retention(RUNTIME) but are only read by Shield during build-time processing).
Related
- Excluded Packages — Exclude entire packages
- Protections Overview — All available protections
- Troubleshooting — Fixing issues caused by obfuscation