/

Annotations

Shield provides three annotations for fine-grained control over which protections apply to individual classes, methods, fields, and constructors.


Available Annotations

AnnotationEffectUse Case
@KeepExcludes from all protectionsReflection, JNI, serialization
@DoNotObfuscatePrevents name obfuscation onlyElements that must keep their name but can be otherwise protected
@ExcludeExcludes from specific protectionsSelective 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

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
    }
}

Kotlin

Kotlin
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

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
}

Kotlin

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
    }
}

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

NameProtection
"NameObfuscation"Name obfuscation (renaming)
"StringEncryption"String literal encryption
"ControlFlowMatrix"Control flow obfuscation
"ConstantMutation"Constant value mutation
"DebugInfoRemoval"Debug metadata removal

Java

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();

Kotlin

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
}

Annotation Targets

All three annotations support the same targets:

TargetExample
TYPEClass, interface, enum
METHODInstance and static methods
FIELDInstance and static fields
CONSTRUCTORClass 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:

AnnotationSource
@androidx.annotation.KeepAndroidX
@android.support.annotation.KeepAndroid Support Library
@ProguardKeepCustom ProGuard convention
@DoNotRenameCommon 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:

Groovy
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).


Previous
Debug Removal