Files
VibeCoding/.agents/skills/r8-analyzer/references/REFLECTION-GUIDE.md

139 lines
4.3 KiB
Markdown

A categorized summary of the keep rule examples, including the code patterns to
look for (imports/usage) and the corresponding suggested rules.
### 1. Reflection: Classes Loaded by Name
**Scenario:** A library or app loads a class dynamically using a string name
- **Look for:**
`Class.forName("...")`,
`getDeclaredConstructor().newInstance()`, or interfaces used for dynamic loading.
- **Example Code:**
`kotlin
val taskClass = Class.forName(className)
val task = taskClass.getDeclaredConstructor().newInstance() as StartupTask`
- **Suggested Keep Rule:**
\`\`\`proguard
-keep class \* implements com.example.library.StartupTask {
(); } \`\`\`
### 2. Reflection: Classes Passed using `::class.java`
**Scenario:** An app passes a class reference directly to a library function.
- **Look for:** `::class.java` (Kotlin) or `.class` (Java) passed as an argument.
- **Example Code:**
`kotlin
fun <T> register(clazz: Class<T>) { }
// Usage:
register(MyService::class.java)`
- **Suggested Keep Rule:**
\`\`\`proguard
# Keep the class itself (R8 usually handles this, but explicit rules ensure stability)
-keep class com.example.app.MyService {
(); } \`\`\`
### 3. Annotation-Based Reflection (Methods/Classes)
**Scenario:** Using custom annotations to mark methods or classes for reflective
execution.
**Look for:** Custom `@interface` definitions and `getDeclaredMethods()`
filtered by annotation.
**Example Code:**
`kotlin
annotation class ReflectiveExecutor
// Logic: find methods annotated with @ReflectiveExecutor and invoke them`
- **Suggested Keep Rule:** \`\`\`proguard # Keep the annotation itself -keep @interface com.example.library.ReflectiveExecutor
# Keep members of any class annotated with this specific annotation
-keepclassmembers class \* {
@com.example.library.ReflectiveExecutor \*;
}
\`\`\`
### 4. Optional Dependencies (Soft Dependencies)
**Scenario:** A core library checks if an optional module is present in the
classpath.
- **Look for:** `try-catch` blocks around `Class.forName()` used to toggle features.
- **Example Code:** \`\`\`kotlin private const val VIDEO_TRACKER_CLASS = "com.example.analytics.video.VideoEventTracker"
try {
Class.forName(VIDEO_TRACKER_CLASS).getDeclaredConstructor().newInstance()
} catch (e: ClassNotFoundException) { /\* skip feature \*/ }
\`\`\`
- **Suggested Keep Rule:** `proguard
# Preserve the optional class so the check doesn't fail due to shrinking
-keep class com.example.analytics.video.VideoEventTracker {
<init>();
}`
### 5. Accessing Private Members
**Scenario:** Using reflection to access internal fields or methods not exposed
with public APIs.
- **Look for:** `getDeclaredField("...")` or `getDeclaredMethod("...")` followed by `isAccessible = true`.
- **Example Code:**
`kotlin
val secretField = instance::class.java.getDeclaredField("secretMessage")
secretField.isAccessible = true`
- **Suggested Keep Rule:**
\`\`\`proguard
# Specifically keep the private field/method by name and type
-keepclassmembers class com.example.LibraryClass {
private java.lang.String secretMessage;
}
\`\`\`
### 6. Parcelable (Manual Implementation)
**Scenario:** Implementing `Parcelable` without using the `@Parcelize`
annotation.
- **Look for:** `implements Parcelable` and a static `CREATOR` field.
- **Example Code:**
`kotlin
class MyData : Parcelable {
// Manual implementation with CREATOR field
}`
- **Suggested Keep Rule:**
*(Note: If using `import kotlinx.parcelize.Parcelize`, R8/ProGuard rules are
generated automatically. If manual, use the following:)*
`proguard
-keepclassmembers class * implements android.os.Parcelable {
static android.os.Parcelable$Creator CREATOR;
}`
### 7. Enums and Obfuscation
**Scenario:** App uses `Enum.valueOf("STRING_NAME")` indirectly (e.g.,using JSON
deserialization) and the enum names get obfuscated.
- **Look for:** Unnecessary generic Enum keep rules in ProGuard files.
- **Example Code:**
\`\`\`proguard
# Unnecessary rule
-keepclassmembers enum \* { \*; }
\`\`\`
- **Suggested Keep Rule:**
\*(Note: The default `proguard-android-optimize.txt` already contains the optimal
rules for Enums (keeping `values()` and `valueOf(String)`). Any additional
manual rules for Enums are redundant.) # No manual rule needed. Use default
proguard-android-optimize.txt.