svharness 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +531 -0
- package/bin/cli.js +3 -0
- package/dist/adapters/_frontmatter.js +24 -0
- package/dist/adapters/claude-code.js +12 -0
- package/dist/adapters/codechat.js +12 -0
- package/dist/adapters/cursor.js +19 -0
- package/dist/adapters/generic.js +19 -0
- package/dist/adapters/index.js +26 -0
- package/dist/adapters/qoder.js +12 -0
- package/dist/commands/apply.js +272 -0
- package/dist/commands/init.js +420 -0
- package/dist/core/agent-injector.js +192 -0
- package/dist/core/next-steps.js +91 -0
- package/dist/core/render-meta.js +81 -0
- package/dist/core/repomix-pack.js +54 -0
- package/dist/core/scaffold.js +93 -0
- package/dist/core/state.js +80 -0
- package/dist/index.js +239 -0
- package/dist/types.js +5 -0
- package/dist/utils/baseline-copy.js +591 -0
- package/dist/utils/baseline-defaults.js +106 -0
- package/dist/utils/logger.js +56 -0
- package/dist/utils/validate-args.js +132 -0
- package/dist/utils/version.js +23 -0
- package/dist/wiki/abort.js +30 -0
- package/dist/wiki/config.js +79 -0
- package/dist/wiki/defaults.js +16 -0
- package/dist/wiki/envLoader.js +78 -0
- package/dist/wiki/index.js +29 -0
- package/dist/wiki/openaiCompat.js +219 -0
- package/dist/wiki/repowikiCanonicalSections.js +67 -0
- package/dist/wiki/repowikiCheckpoint.js +106 -0
- package/dist/wiki/repowikiConfig.js +9 -0
- package/dist/wiki/repowikiGit.js +73 -0
- package/dist/wiki/repowikiIndexer.js +824 -0
- package/dist/wiki/repowikiMarkdownPost.js +123 -0
- package/dist/wiki/repowikiMetadataContent.js +64 -0
- package/dist/wiki/repowikiMetadataJson.js +15 -0
- package/dist/wiki/repowikiScanner.js +156 -0
- package/dist/wiki/repowikiStructureNav.js +286 -0
- package/dist/wiki/repowikiStructureNormalize.js +218 -0
- package/dist/wiki/wikiStructureXml.js +316 -0
- package/dist/wiki/wikiTasksWriter.js +127 -0
- package/package.json +57 -0
- package/templates/_shared/apply-skills/harness-apply-skills-main.md +91 -0
- package/templates/_shared/build-rules/harness-build-rule-agent-agnostic.md +35 -0
- package/templates/_shared/build-rules/harness-build-rule-chinese-only.md +49 -0
- package/templates/_shared/build-rules/harness-build-rule-memory-write.md +31 -0
- package/templates/_shared/build-rules/harness-build-rule-orchestrator-flow.md +25 -0
- package/templates/_shared/build-rules/harness-build-rule-skills-tasks-output.md +35 -0
- package/templates/_shared/build-rules/harness-build-rule-specs-schema.md +32 -0
- package/templates/_shared/build-rules/harness-build-rule-user-interaction.md +63 -0
- package/templates/_shared/build-skills/harness-build-skill-knowledge-builder.md +120 -0
- package/templates/_shared/build-skills/harness-build-skill-orchestrator.md +87 -0
- package/templates/_shared/build-skills/harness-build-skill-spec-builder.md +85 -0
- package/templates/_shared/build-skills/harness-build-skill-wiki-writer.md +77 -0
- package/templates/_shared/meta/AGENTS.md.ejs +53 -0
- package/templates/_shared/meta/CHANGELOG.md.ejs +15 -0
- package/templates/_shared/meta/README.md.ejs +51 -0
- package/templates/_shared/meta/VERSION.ejs +1 -0
- package/templates/_shared/meta/harness.yaml.ejs +52 -0
- package/templates/_shared/skeleton/agent-env/memory/categories/.gitkeep +1 -0
- package/templates/_shared/skeleton/agent-env/memory/inbox/.gitkeep +1 -0
- package/templates/_shared/skeleton/agent-env/skills/.gitkeep +1 -0
- package/templates/_shared/skeleton/agent-env/tools/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/baseline/code/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/baseline/repomix/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/baseline/wiki/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/raw/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/requirements/.gitkeep +1 -0
- package/templates/_shared/skeleton/commands/install/.gitkeep +1 -0
- package/templates/_shared/skeleton/commands/update/.gitkeep +1 -0
- package/templates/_shared/skeleton/specs/behavior/schema.json +39 -0
- package/templates/_shared/skeleton/specs/interfaces/schema.json +38 -0
- package/templates/_shared/skeleton/specs/signals/schema.json +37 -0
- package/templates/_shared/skeleton/specs/ui/schema.json +44 -0
- package/templates/_shared/skeleton/tasks/templates/.gitkeep +0 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-compose-mandatory.mdc +49 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-coroutines-scope.mdc +52 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-hilt-injection.mdc +47 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-mvi-layering.mdc +58 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/SKILL.md +260 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/gradle-module-patterns.md +66 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/implementation-checklist.md +45 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/udf-data-flow.md +80 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/SKILL.md +79 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/interact.md +83 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/journeys.md +97 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/SKILL.md +162 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/canonical-sources.md +116 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/diagnostics.md +182 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/report-template.md +135 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/scoring.md +277 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/search-playbook.md +303 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/scripts/compose-reports.init.gradle +58 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-state/SKILL.md +196 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/SKILL.md +192 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/composable-api-guide.md +123 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/performance-recipes.md +97 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/state-patterns.md +93 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-kotlin-coroutines/SKILL.md +167 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/SKILL.md +45 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/CONFIGURATION.md +44 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/KEEP-RULES-IMPACT-HIERARCHY.md +83 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REDUNDANT-RULES.md +222 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REFLECTION-GUIDE.md +139 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/topic/performance/app-optimization/enable-app-optimization.md +176 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/training/testing/other-components/ui-automator.md +312 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/SKILL.md +87 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/analysis-of-the-project-and-layout.md +42 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md +168 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md +183 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/identify-optimal-xml-candidate.md +31 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/xml-layout-migration.md +86 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-aidl-thread.md +29 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-lifecycle-awareness.md +32 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-mvc-layering.md +32 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-view-binding.md +33 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-xml-styling.md +27 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-cmake-explicit-sources.md +31 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-header-guards.md +34 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-include-layering.md +39 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-no-cyclic-deps.md +29 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-raii.md +30 -0
- package/templates/python/skeleton/agent-env/rules/seed-context-managers.md +60 -0
- package/templates/python/skeleton/agent-env/rules/seed-docstrings.md +48 -0
- package/templates/python/skeleton/agent-env/rules/seed-import-order.md +49 -0
- package/templates/python/skeleton/agent-env/rules/seed-pep8-naming.md +45 -0
- package/templates/python/skeleton/agent-env/rules/seed-type-annotations.md +43 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-controlled-component.md +43 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-effect-cleanup.md +43 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-hook-rules.md +42 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-key-stability.md +39 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-no-props-drilling.md +43 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-r8-analyzer
|
|
3
|
+
description: 分析 Android 构建文件和 R8 keep 规则,识别冗余规则、过于宽泛的包级规则,以及覆盖了库消费者 keep 规则的规则。当开发者想要优化应用大小、移除冗余或过于宽泛的 keep 规则,或排查 Proguard 配置问题时使用。
|
|
4
|
+
license: Complete terms in LICENSE.txt
|
|
5
|
+
metadata:
|
|
6
|
+
author: Google LLC
|
|
7
|
+
keywords:
|
|
8
|
+
- R8
|
|
9
|
+
- proguard
|
|
10
|
+
- keep 规则
|
|
11
|
+
- 应用大小
|
|
12
|
+
- 优化
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 核心工作流
|
|
16
|
+
|
|
17
|
+
- [ ] 步骤 1:创建名为 R8_Configuration_Analysis.md 的文件(如已存在则复用),用于存储输出
|
|
18
|
+
- [ ] 步骤 2:通过查看代码库中的 build.gradle、build.gradle.kts、gradle.properties 来检查 R8 配置,以 [references/CONFIGURATION.md](references/CONFIGURATION.md) 作为参考。通知开发者并将分析结果添加到报告文件中
|
|
19
|
+
- [ ] 步骤 3:如果 AGP 版本低于 9,建议升级到 AGP 9.0,因为 AGP 9.0 包含[优化](references/android/topic/performance/app-optimization/enable-app-optimization.md)。
|
|
20
|
+
- [ ] 步骤 4:查看代码库中的 proguard 文件,并按以下特定顺序评估每条 keep 规则:
|
|
21
|
+
a. **库检查**:根据 [references/REDUNDANT-RULES.md](references/REDUNDANT-RULES.md) 检查规则。如果应用的 keep 规则针对的是库(Google、AndroidX、Kotlin、Kotlinx、Room、Gson、Retrofit),告知用户这些规则不需要并建议移除。
|
|
22
|
+
b. **影响分析**:对于剩余的 keep 规则,根据 [references/KEEP-RULES-IMPACT-HIERARCHY.md](references/KEEP-RULES-IMPACT-HIERARCHY.md) 中定义的影响层级进行评估。
|
|
23
|
+
- [ ] 步骤 5:根据 [references/KEEP-RULES-IMPACT-HIERARCHY.md](references/KEEP-RULES-IMPACT-HIERARCHY.md) 中定义的层级,识别剩余 keep 规则中的包含关系,并建议移除更宽泛的 keep 规则。
|
|
24
|
+
- [ ] 步骤 6:对于每条剩余的 keep 规则,通过检查受影响代码及相邻文件来详细分析规则存在的原因。查找相关包中的反射使用,并参考 [references/REFLECTION-GUIDE.md](references/REFLECTION-GUIDE.md) 为场景建议更窄更具体的 keep 规则。
|
|
25
|
+
- [ ] 步骤 7:对于每条 keep 规则,简明扼要地告知需要采取的操作——该规则是需要移除还是需要细化。
|
|
26
|
+
- [ ] 步骤 8:keep 规则分析完成后,根据 [references/KEEP-RULES-IMPACT-HIERARCHY.md](references/KEEP-RULES-IMPACT-HIERARCHY.md) 定义的对代码库的影响层级对分析结果排序。
|
|
27
|
+
- [ ] 步骤 9:建议用户使用 [UI Automator](references/android/training/testing/other-components/ui-automator.md) 运行测试,以评估建议的更改没有问题。
|
|
28
|
+
|
|
29
|
+
## 强制规则
|
|
30
|
+
|
|
31
|
+
- 不要修改 keep 规则文件
|
|
32
|
+
- 不要说明每条 keep 规则的级别
|
|
33
|
+
- 如果某个部分没有 keep 规则需要报告,不要生成该部分的报告内容
|
|
34
|
+
- 不要提及生成的文件
|
|
35
|
+
- 不要提及执行期间发生的异常
|
|
36
|
+
- 不要提及 R8 的好处
|
|
37
|
+
- 不要提及本技能的任何文件
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 必须遵守的约束规则
|
|
42
|
+
|
|
43
|
+
> rules 引用路径:`../rules/<rule-name>.mdc`
|
|
44
|
+
|
|
45
|
+
无(本技能为 R8 规则分析,不涉及代码生成)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
To achieve maximum utilization of R8, the codebase must be configured correctly
|
|
2
|
+
depending on the build script language (Kotlin DSL vs. Groovy DSL).
|
|
3
|
+
|
|
4
|
+
## 1. App Modules (`com.android.application`)
|
|
5
|
+
|
|
6
|
+
The app's `build.gradle` or `build.gradle.kts` file should enable minification
|
|
7
|
+
and resource shrinking within the `release` build type or the apps custom build
|
|
8
|
+
type for release and performance testing. It MUST use the optimized default file
|
|
9
|
+
(`proguard-android-optimize.txt`).
|
|
10
|
+
|
|
11
|
+
**Kotlin DSL (`build.gradle.kts`):**
|
|
12
|
+
|
|
13
|
+
buildTypes {
|
|
14
|
+
getByName("release") {
|
|
15
|
+
isMinifyEnabled = true
|
|
16
|
+
isShrinkResources = true
|
|
17
|
+
proguardFiles(
|
|
18
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
19
|
+
"proguard-rules.pro"
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
**Groovy DSL (`build.gradle`):**
|
|
25
|
+
|
|
26
|
+
buildTypes {
|
|
27
|
+
release {
|
|
28
|
+
minifyEnabled = true
|
|
29
|
+
shrinkResources = true
|
|
30
|
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
## 2. `gradle.properties` Flags
|
|
35
|
+
|
|
36
|
+
**Full Mode:** R8 Full Mode enables the entire optimizations
|
|
37
|
+
|
|
38
|
+
- **AGP 8.0+** : Enabled by default. Ensure `android.enableR8.fullMode=false` is **NOT** present.
|
|
39
|
+
- **Pre-AGP 8.0** : Should be explicitly enabled with `android.enableR8.fullMode=true`.
|
|
40
|
+
|
|
41
|
+
**Optimized Resource Shrinking:** If the AGP version of the project is less than
|
|
42
|
+
9.0 and more than 8.6, explicitly enable the new resource shrinker:
|
|
43
|
+
|
|
44
|
+
android.r8.optimizedResourceShrinking=true
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Keep rules prevent optimization of R8, these rules are listed in the order of
|
|
2
|
+
the scope of what it retains in the codebase.
|
|
3
|
+
|
|
4
|
+
## 1. Package-Wide Wildcards
|
|
5
|
+
|
|
6
|
+
The following types of keep rules prevents all the optimization of R8 in a
|
|
7
|
+
package, these must be avoided at any costs and must be refined to target a
|
|
8
|
+
specific class or classes.
|
|
9
|
+
|
|
10
|
+
-keep class com.example.package.** { *; } - Prevents optimization of all the classess including members in the package and subpackages
|
|
11
|
+
-keep class com.example.package.* { *; } - Prevents optimization of all the classes including members in the package
|
|
12
|
+
-keep class **.package.** { *; } - Prevents optimization of all the classess including members in all the package containing name - package.
|
|
13
|
+
|
|
14
|
+
Depending on the package level the number of classes gets affected changes, so
|
|
15
|
+
if the package level is higher, more classes are affected. Suggest to refine
|
|
16
|
+
the keep rule
|
|
17
|
+
|
|
18
|
+
## 2. Inversion operator
|
|
19
|
+
|
|
20
|
+
Avoid using the inversion operator ! in keep rules because it will
|
|
21
|
+
unintentionally prevent optimization in every class in your application. So if
|
|
22
|
+
you have any keep rule with !operator, make sure you remove that with a narrow
|
|
23
|
+
and specific keep rule
|
|
24
|
+
|
|
25
|
+
-keep class !com.example.MyClass{*;}
|
|
26
|
+
|
|
27
|
+
This keeps the entire app
|
|
28
|
+
other than this class. Optimization are disabled for the entire class other
|
|
29
|
+
than this class.
|
|
30
|
+
|
|
31
|
+
## 3. Keep Rules for both class and members
|
|
32
|
+
|
|
33
|
+
Keep rules with -keep option and wildcard(`*`) inside braces forces R8 to retain
|
|
34
|
+
specific classes and their members exactly as defined. These type of keep rules
|
|
35
|
+
prevent any optimization in the entire class and keeps the entire class
|
|
36
|
+
|
|
37
|
+
-keep class com.example.MyClass { *; }
|
|
38
|
+
|
|
39
|
+
## 4. Keepclassmembers
|
|
40
|
+
|
|
41
|
+
Keep rules with -keepclassmembers and wildcard(`*`) inside braces option Forces
|
|
42
|
+
R8 to retain the members that are defined.
|
|
43
|
+
|
|
44
|
+
-keepclassmembers class com.example.MyClass { *; }
|
|
45
|
+
|
|
46
|
+
## 5. Modifiers with Keep Specification
|
|
47
|
+
|
|
48
|
+
-Keeps the class and **all** members, but uses modifiers to allow specific
|
|
49
|
+
optimizations (like obfuscation). Retains significant code (members) but allows
|
|
50
|
+
some flexibility.
|
|
51
|
+
|
|
52
|
+
-keep,allowobfuscation class com.example.MyClass { *; }
|
|
53
|
+
-keep,allowshrinking class com.example.MyClass { *; }
|
|
54
|
+
|
|
55
|
+
### 6. Modifiers with specific method but no modifier
|
|
56
|
+
|
|
57
|
+
Keeps the class and modifier but no optimizations are enabled
|
|
58
|
+
|
|
59
|
+
-keep class com.example.MyClass { void myMethod(); }
|
|
60
|
+
|
|
61
|
+
## 7. Class-Name Only Preservation
|
|
62
|
+
|
|
63
|
+
Keeps only the class name. R8 will remove all methods and fields if they are not
|
|
64
|
+
used.
|
|
65
|
+
|
|
66
|
+
-keep class com.example.MyClass
|
|
67
|
+
|
|
68
|
+
## 8. Modifiers without Member Specification
|
|
69
|
+
|
|
70
|
+
Keeps the class entry point using modifiers, but implies no specific member
|
|
71
|
+
retention logic in the rule itself
|
|
72
|
+
|
|
73
|
+
-keep,allowobfuscation class com.example.MyClass
|
|
74
|
+
-keep,allowshrinking class com.example.MyClass
|
|
75
|
+
-keep,allowaccessmodification class com.example.MyClass
|
|
76
|
+
|
|
77
|
+
## 9. Conditional Keep Rules
|
|
78
|
+
|
|
79
|
+
Only triggers if specific conditions are met (e.g., if class members exist).
|
|
80
|
+
These are the most narrow and optimization-friendly rules.
|
|
81
|
+
|
|
82
|
+
-keepclassmembers class com.example.MyClass { <fields>; }
|
|
83
|
+
-keepclasseswithmembers class * { native <methods>; }
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
This document outlines common "bad" or redundant keep rules for standard Android
|
|
2
|
+
development and popular libraries. Modern toolchains and libraries include their
|
|
3
|
+
own consumer keep rules embedded in their AAR/JAR files, making many manual
|
|
4
|
+
configurations unnecessary or even harmful to code optimization.
|
|
5
|
+
|
|
6
|
+
*** ** * ** ***
|
|
7
|
+
|
|
8
|
+
## Case: Global Keep Rules
|
|
9
|
+
|
|
10
|
+
**Common Mistakes:**
|
|
11
|
+
`proguard
|
|
12
|
+
-dontshrink
|
|
13
|
+
-dontobfuscate
|
|
14
|
+
-dontoptimize`
|
|
15
|
+
|
|
16
|
+
**The Fix:** These keep rules completely disable the core optimizations of R8
|
|
17
|
+
for the entire codebase. They must be removed from the codebase.
|
|
18
|
+
|
|
19
|
+
*** ** * ** ***
|
|
20
|
+
|
|
21
|
+
## Case: Android Components
|
|
22
|
+
|
|
23
|
+
Keep rules required for Android components like Activity, Fragment, ViewModel,
|
|
24
|
+
Views, Services or Broadcast receivers are redundant. AAPT2 and R8 contain the
|
|
25
|
+
logic to automatically keep components declared in the `AndroidManifest.xml` or
|
|
26
|
+
referenced in XML layout files.
|
|
27
|
+
|
|
28
|
+
**Common Mistakes:**
|
|
29
|
+
`proguard
|
|
30
|
+
-keep public class * extends android.app.Activity
|
|
31
|
+
-keep public class * extends android.app.Service
|
|
32
|
+
-keep public class * extends android.view.View
|
|
33
|
+
-keepclassmembers class * extends android.app.Fragment { public void *(android.view.View); }`
|
|
34
|
+
|
|
35
|
+
**The Fix:** Delete these manual rules. AAPT2 handles this automatically.
|
|
36
|
+
|
|
37
|
+
*** ** * ** ***
|
|
38
|
+
|
|
39
|
+
## Case: Official Android and Kotlin Libraries
|
|
40
|
+
|
|
41
|
+
Keep rules targeting official library packages like AndroidX, Kotlin, and
|
|
42
|
+
Kotlinx are redundant as they are bundled within the libraries themselves.
|
|
43
|
+
Manual rules are often broader than what is strictly needed.
|
|
44
|
+
|
|
45
|
+
**Common Mistakes:**
|
|
46
|
+
`proguard
|
|
47
|
+
-keep class androidx.** { *; }
|
|
48
|
+
-keep class kotlinx.** { *; }
|
|
49
|
+
-keep class kotlin.** { *; }`
|
|
50
|
+
|
|
51
|
+
**The Fix:** Delete these manual rules. Rely on the consumer keep rules packaged
|
|
52
|
+
within these dependencies.
|
|
53
|
+
|
|
54
|
+
*** ** * ** ***
|
|
55
|
+
|
|
56
|
+
## Case: Gson
|
|
57
|
+
|
|
58
|
+
### Overly Broad Data Model Rules
|
|
59
|
+
|
|
60
|
+
The most common mistake is keeping entire packages of data models (POJOs/DTOs),
|
|
61
|
+
keeping data models at all for deserialization is unnecessary.
|
|
62
|
+
|
|
63
|
+
-keep class com.example.app.models.** { *; }
|
|
64
|
+
-keep class com.example.app.package.models.* { *; }
|
|
65
|
+
|
|
66
|
+
### Redundant Interface \& Adapter Rules
|
|
67
|
+
|
|
68
|
+
These rules added for TypeAdapter are unnecessary and are already covered by
|
|
69
|
+
the library, and prevent R8 from effectively shrinking and optimizing custom
|
|
70
|
+
adapters. R8 can determine if the adapter implementation are used. Keeping them
|
|
71
|
+
globally prevents the removal of unused adapter implementations.
|
|
72
|
+
|
|
73
|
+
-keep class * extends com.google.gson.TypeAdapter
|
|
74
|
+
-keep class * implements com.google.gson.TypeAdapterFactory
|
|
75
|
+
-keep class * implements com.google.gson.JsonSerializer
|
|
76
|
+
-keep class * implements com.google.gson.JsonDeserializer
|
|
77
|
+
|
|
78
|
+
### Unnecessary TypeToken Rules
|
|
79
|
+
|
|
80
|
+
There is no need to handle generic type erasure, Gson's own rules handle the
|
|
81
|
+
necessary `TypeToken` preservation.
|
|
82
|
+
|
|
83
|
+
-keep class com.google.gson.reflect.TypeToken { *; }
|
|
84
|
+
-keep class * extends com.google.gson.reflect.TypeToken
|
|
85
|
+
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
|
|
86
|
+
|
|
87
|
+
### Internal and Example Packages
|
|
88
|
+
|
|
89
|
+
Keeping internal library logic prevents the compiler from stripping away dead
|
|
90
|
+
code within the library.
|
|
91
|
+
|
|
92
|
+
-keep class com.google.gson.internal.** { *; }
|
|
93
|
+
-keep class com.google.gson.internal.reflect.** { *; }
|
|
94
|
+
-keep class com.google.gson.internal.UnsafeAllocator { *; }
|
|
95
|
+
-keep class com.google.gson.stream.** { *; }
|
|
96
|
+
|
|
97
|
+
- **Keeps Unused Code:** Prevents R8 from removing models that are never actually used in the code.
|
|
98
|
+
- **Prevents Method Stripping:** Keeps all getters, setters, `toString()`, `equals()`, and `hashCode()` methods, even if they are never called.
|
|
99
|
+
- **Blocks Obfuscation:** Prevents the class names from being obfuscated, which is unnecessary for Gson if you use `@SerializedName`.
|
|
100
|
+
|
|
101
|
+
**The Fix:**
|
|
102
|
+
|
|
103
|
+
1. Use `@SerializedName` on every field in your data classes uses so that the field is retained after R8 optimization
|
|
104
|
+
2. Modern Gson (**v2.11.0+** ) bundles its own rules ([View Gson's embedded
|
|
105
|
+
ProGuard
|
|
106
|
+
rules](https://github.com/google/gson/blob/main/gson/src/main/resources/META-INF/proguard/gson.pro)). The bundled keep rules retains the `@SerializedName` annotated fields. If you are on an older version, move towards Gson version 2.11 because it has the necessary keep rules and delete the keep rules that target the classes used for gson serialization and deserialization
|
|
107
|
+
|
|
108
|
+
*** ** * ** ***
|
|
109
|
+
|
|
110
|
+
## Case: Retrofit
|
|
111
|
+
|
|
112
|
+
Retrofit has shipped with its own consumer keep rules from 2.9.0 and higher, so
|
|
113
|
+
any keep rules for the library or classes depending on Retrofit is detrimental
|
|
114
|
+
to the optimization process.
|
|
115
|
+
|
|
116
|
+
### Blanket Library Preservation
|
|
117
|
+
|
|
118
|
+
This is the most harmful Retrofit rule as it disables any shrinking for the
|
|
119
|
+
entire library.
|
|
120
|
+
|
|
121
|
+
-keep class retrofit2.** { *; }
|
|
122
|
+
-keep class retrofit2.api.** { *; }
|
|
123
|
+
-keep class com.package.example.retrofit.api.** { *; }
|
|
124
|
+
|
|
125
|
+
### Manual Annotation Keeps
|
|
126
|
+
|
|
127
|
+
Retrofit's consumer rules automatically keep the interfaces annotated with
|
|
128
|
+
`@GET`, `@POST`, `@DELETE`, `@PUT`, `@HEAD`, `@OPTIONS`, `@PATCH`, making these
|
|
129
|
+
manual rules obsolete.
|
|
130
|
+
|
|
131
|
+
`-keepclasseswithmembers class * { @retrofit2.http.* <methods>; }`
|
|
132
|
+
|
|
133
|
+
### Redundant Network Response and Adapter Rules
|
|
134
|
+
|
|
135
|
+
Network responses and third-party adapter wrappers (like RxJava) are often
|
|
136
|
+
overly preserved by developers out of caution.
|
|
137
|
+
|
|
138
|
+
-keep,allowobfuscation,allowshrinking class retrofit2.Response
|
|
139
|
+
-keep class retrofit2.adapter.rxjava2.Result { *; }
|
|
140
|
+
|
|
141
|
+
Fix: Verify you are using Retrofit 2.9.0 and higher. Retrofit from 2.9.0 bundles
|
|
142
|
+
rules that detect its own HTTP annotations (@GET, @POST) ([View Retrofit's
|
|
143
|
+
embedded ProGuard
|
|
144
|
+
rules](https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro)).
|
|
145
|
+
It will automatically keep the method signatures it needs to work.
|
|
146
|
+
|
|
147
|
+
*** ** * ** ***
|
|
148
|
+
|
|
149
|
+
## Case: Kotlin Coroutines
|
|
150
|
+
|
|
151
|
+
Kotlin Coroutines comes heavily optimized out of the box with embedded R8 rules
|
|
152
|
+
(`kotlinx-coroutines-core` includes its own rules).
|
|
153
|
+
|
|
154
|
+
### Blanket Coroutine Library Rules
|
|
155
|
+
|
|
156
|
+
Keeping everything under `kotlinx.coroutines` is extremely detrimental to app
|
|
157
|
+
size, as coroutines contain a vast amount of internal APIs that aren't used.
|
|
158
|
+
|
|
159
|
+
`-keepclassmembers class kotlinx.coroutines.** { *; }`
|
|
160
|
+
|
|
161
|
+
### Redundant Internal Continuations
|
|
162
|
+
|
|
163
|
+
These low-level coroutine elements are preserved safely by the library's own
|
|
164
|
+
consumer rules. Manually adding these prevents R8 from performing internal
|
|
165
|
+
optimizations (such as removing unused continuations or inlining).
|
|
166
|
+
|
|
167
|
+
-keepclassmembers class kotlin.coroutines.SafeContinuation { *; }
|
|
168
|
+
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
|
|
169
|
+
|
|
170
|
+
### Dispatcher and Exception Handler Rules
|
|
171
|
+
|
|
172
|
+
Sometimes developers notice crashes related to Missing Classes on old Android
|
|
173
|
+
versions and add these rules, but if you are using an up-to-date version of
|
|
174
|
+
Coroutines, these are handled automatically or are not an issue.
|
|
175
|
+
|
|
176
|
+
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
|
|
177
|
+
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
|
|
178
|
+
-keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}
|
|
179
|
+
-keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
|
|
180
|
+
|
|
181
|
+
**Fix** Remove any broad `kotlinx` keep rules. Coroutines (**v1.7.0+** ) bundle
|
|
182
|
+
the necessary keep rules ([View Coroutines' embedded ProGuard
|
|
183
|
+
rules](https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro)).
|
|
184
|
+
|
|
185
|
+
*** ** * ** ***
|
|
186
|
+
|
|
187
|
+
## Case: Parcelable
|
|
188
|
+
|
|
189
|
+
**Common Mistakes:** Legacy projects often contain `-keep class * implements
|
|
190
|
+
android.os.Parcelable { public static final android.os.Parcelable$Creator *; }`.
|
|
191
|
+
|
|
192
|
+
**The Fix:**
|
|
193
|
+
|
|
194
|
+
1. Add the `kotlin-parcelize` plugin.
|
|
195
|
+
2. **Use `@Parcelize`:** Replace manual `writeToParcel` logic with the `@Parcelize` annotation.
|
|
196
|
+
3. **Delete All Parcelable Rules:** The plugin automatically generates the required rules.
|
|
197
|
+
4. The default proguard file `proguard-android-optimize.txt` contains the keep rules for keeping all the parcelable classes
|
|
198
|
+
5. **Ideal Rule:** **None.** Delete all manual Parcelable keeps.
|
|
199
|
+
|
|
200
|
+
*** ** * ** ***
|
|
201
|
+
|
|
202
|
+
## Case: Room Database
|
|
203
|
+
|
|
204
|
+
**Common Mistakes:** Keeping DAO interfaces or the generated `_Impl` classes
|
|
205
|
+
manually.
|
|
206
|
+
|
|
207
|
+
-keep class * extends androidx.room.RoomDatabase
|
|
208
|
+
-keep class *_*Impl { *; }
|
|
209
|
+
|
|
210
|
+
**The Fix:** Room generates its own ProGuard rules for the code it creates.
|
|
211
|
+
Manual rules are redundant and prevent R8 from optimizing the database access
|
|
212
|
+
layers.
|
|
213
|
+
|
|
214
|
+
- **Ideal Rule:** **None.** Delete all manual Room or DAO keeps.
|
|
215
|
+
|
|
216
|
+
*** ** * ** ***
|
|
217
|
+
|
|
218
|
+
## Summary
|
|
219
|
+
|
|
220
|
+
If you have updated your libraries to the versions mentioned, your
|
|
221
|
+
`proguard-rules.pro` must not contain any keep rules for the libraries
|
|
222
|
+
mentioned here.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
A categorized summary of the keep rule examples, including the code patterns to
|
|
2
|
+
look for (imports/usage) and the corresponding suggested rules.
|
|
3
|
+
|
|
4
|
+
### 1. Reflection: Classes Loaded by Name
|
|
5
|
+
|
|
6
|
+
**Scenario:** A library or app loads a class dynamically using a string name
|
|
7
|
+
|
|
8
|
+
- **Look for:**
|
|
9
|
+
`Class.forName("...")`,
|
|
10
|
+
`getDeclaredConstructor().newInstance()`, or interfaces used for dynamic loading.
|
|
11
|
+
|
|
12
|
+
- **Example Code:**
|
|
13
|
+
`kotlin
|
|
14
|
+
val taskClass = Class.forName(className)
|
|
15
|
+
val task = taskClass.getDeclaredConstructor().newInstance() as StartupTask`
|
|
16
|
+
|
|
17
|
+
- **Suggested Keep Rule:**
|
|
18
|
+
\`\`\`proguard
|
|
19
|
+
|
|
20
|
+
-keep class \* implements com.example.library.StartupTask {
|
|
21
|
+
(); } \`\`\`
|
|
22
|
+
|
|
23
|
+
### 2. Reflection: Classes Passed using `::class.java`
|
|
24
|
+
|
|
25
|
+
**Scenario:** An app passes a class reference directly to a library function.
|
|
26
|
+
|
|
27
|
+
- **Look for:** `::class.java` (Kotlin) or `.class` (Java) passed as an argument.
|
|
28
|
+
- **Example Code:**
|
|
29
|
+
`kotlin
|
|
30
|
+
fun <T> register(clazz: Class<T>) { }
|
|
31
|
+
// Usage:
|
|
32
|
+
register(MyService::class.java)`
|
|
33
|
+
|
|
34
|
+
- **Suggested Keep Rule:**
|
|
35
|
+
\`\`\`proguard
|
|
36
|
+
|
|
37
|
+
# Keep the class itself (R8 usually handles this, but explicit rules ensure stability)
|
|
38
|
+
|
|
39
|
+
-keep class com.example.app.MyService {
|
|
40
|
+
(); } \`\`\`
|
|
41
|
+
|
|
42
|
+
### 3. Annotation-Based Reflection (Methods/Classes)
|
|
43
|
+
|
|
44
|
+
**Scenario:** Using custom annotations to mark methods or classes for reflective
|
|
45
|
+
execution.
|
|
46
|
+
|
|
47
|
+
**Look for:** Custom `@interface` definitions and `getDeclaredMethods()`
|
|
48
|
+
filtered by annotation.
|
|
49
|
+
**Example Code:**
|
|
50
|
+
`kotlin
|
|
51
|
+
annotation class ReflectiveExecutor
|
|
52
|
+
// Logic: find methods annotated with @ReflectiveExecutor and invoke them`
|
|
53
|
+
|
|
54
|
+
- **Suggested Keep Rule:** \`\`\`proguard # Keep the annotation itself -keep @interface com.example.library.ReflectiveExecutor
|
|
55
|
+
|
|
56
|
+
# Keep members of any class annotated with this specific annotation
|
|
57
|
+
-keepclassmembers class \* {
|
|
58
|
+
@com.example.library.ReflectiveExecutor \*;
|
|
59
|
+
}
|
|
60
|
+
\`\`\`
|
|
61
|
+
|
|
62
|
+
### 4. Optional Dependencies (Soft Dependencies)
|
|
63
|
+
|
|
64
|
+
**Scenario:** A core library checks if an optional module is present in the
|
|
65
|
+
classpath.
|
|
66
|
+
|
|
67
|
+
- **Look for:** `try-catch` blocks around `Class.forName()` used to toggle features.
|
|
68
|
+
- **Example Code:** \`\`\`kotlin private const val VIDEO_TRACKER_CLASS = "com.example.analytics.video.VideoEventTracker"
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
Class.forName(VIDEO_TRACKER_CLASS).getDeclaredConstructor().newInstance()
|
|
72
|
+
} catch (e: ClassNotFoundException) { /\* skip feature \*/ }
|
|
73
|
+
\`\`\`
|
|
74
|
+
|
|
75
|
+
- **Suggested Keep Rule:** `proguard
|
|
76
|
+
# Preserve the optional class so the check doesn't fail due to shrinking
|
|
77
|
+
-keep class com.example.analytics.video.VideoEventTracker {
|
|
78
|
+
<init>();
|
|
79
|
+
}`
|
|
80
|
+
|
|
81
|
+
### 5. Accessing Private Members
|
|
82
|
+
|
|
83
|
+
**Scenario:** Using reflection to access internal fields or methods not exposed
|
|
84
|
+
with public APIs.
|
|
85
|
+
|
|
86
|
+
- **Look for:** `getDeclaredField("...")` or `getDeclaredMethod("...")` followed by `isAccessible = true`.
|
|
87
|
+
- **Example Code:**
|
|
88
|
+
`kotlin
|
|
89
|
+
val secretField = instance::class.java.getDeclaredField("secretMessage")
|
|
90
|
+
secretField.isAccessible = true`
|
|
91
|
+
|
|
92
|
+
- **Suggested Keep Rule:**
|
|
93
|
+
\`\`\`proguard
|
|
94
|
+
|
|
95
|
+
# Specifically keep the private field/method by name and type
|
|
96
|
+
|
|
97
|
+
-keepclassmembers class com.example.LibraryClass {
|
|
98
|
+
private java.lang.String secretMessage;
|
|
99
|
+
}
|
|
100
|
+
\`\`\`
|
|
101
|
+
|
|
102
|
+
### 6. Parcelable (Manual Implementation)
|
|
103
|
+
|
|
104
|
+
**Scenario:** Implementing `Parcelable` without using the `@Parcelize`
|
|
105
|
+
annotation.
|
|
106
|
+
|
|
107
|
+
- **Look for:** `implements Parcelable` and a static `CREATOR` field.
|
|
108
|
+
- **Example Code:**
|
|
109
|
+
`kotlin
|
|
110
|
+
class MyData : Parcelable {
|
|
111
|
+
// Manual implementation with CREATOR field
|
|
112
|
+
}`
|
|
113
|
+
|
|
114
|
+
- **Suggested Keep Rule:**
|
|
115
|
+
*(Note: If using `import kotlinx.parcelize.Parcelize`, R8/ProGuard rules are
|
|
116
|
+
generated automatically. If manual, use the following:)*
|
|
117
|
+
`proguard
|
|
118
|
+
-keepclassmembers class * implements android.os.Parcelable {
|
|
119
|
+
static android.os.Parcelable$Creator CREATOR;
|
|
120
|
+
}`
|
|
121
|
+
|
|
122
|
+
### 7. Enums and Obfuscation
|
|
123
|
+
|
|
124
|
+
**Scenario:** App uses `Enum.valueOf("STRING_NAME")` indirectly (e.g.,using JSON
|
|
125
|
+
deserialization) and the enum names get obfuscated.
|
|
126
|
+
|
|
127
|
+
- **Look for:** Unnecessary generic Enum keep rules in ProGuard files.
|
|
128
|
+
- **Example Code:**
|
|
129
|
+
\`\`\`proguard
|
|
130
|
+
|
|
131
|
+
# Unnecessary rule
|
|
132
|
+
|
|
133
|
+
-keepclassmembers enum \* { \*; }
|
|
134
|
+
\`\`\`
|
|
135
|
+
- **Suggested Keep Rule:**
|
|
136
|
+
\*(Note: The default `proguard-android-optimize.txt` already contains the optimal
|
|
137
|
+
rules for Enums (keeping `values()` and `valueOf(String)`). Any additional
|
|
138
|
+
manual rules for Enums are redundant.) # No manual rule needed. Use default
|
|
139
|
+
proguard-android-optimize.txt.
|