相信大家最近应该都知道,目前 Google 在整治 keep 滥用行为,建议 App 开启 R8 完整模式,Google 会对 App 进行打分,分数低会有警告认为性能不佳,所以基于这个,Google 开始把 Keep Rule 优化变成一套可量化、可交给 Agent 执行的工程流程。

实际上 Android 项目做 R8 优化一直有一个很烦的问题, minifyEnabled = true 只是开始,因为随着项目增长,App 自己的 proguard-rules.pro、各个内部模块以及第三方 AAR 携带的 consumer rules ,最后会形成一套相当复杂的约束,比如:
- R8 能不能删除某个类
- 能不能 inline 某个方法
- 能不能修改类结构和名字
之前检查这类问题主要都是人自己看居多,比如看到
-keep class com.foo.** { *; },开发者可能会想着它的范围是不是太大,但是不了解项目的话,就比较难判断它究竟影响了 20 个类还是 2000 个类,哪些方法不能无法 inline,哪些字段因此不能缩减,这条规则是 App 自己需要的,还是某个依赖通过 consumer rules 带进来的。
所以这次 Google 新增了 R8 Configuration Analyzer ,它直接用 R8 对整个 App 和配置的理解,把 keep rule 对最终App 造成的影响量化出来,同时 Google 在官方 android/skills 仓库提供了 r8-analyzer Skill,把 Configuration Analyzer 的运行、数据转换、结果分析和报告生成整理成了一套可以交给 Coding Agent 执行的流程。

那 Configuration Analyzer 到底分析了什么?R8 的 keep rule 本质上是在给优化器增加约束,比如:
kotlin
-keep class com.example.feature.** { *; }
从文本上看,这条规则是保留某个 package 下面的类和成员,但对于性能优化来说问题是:
当前这个 Release Build 里到底有多少 class、field、method 被它匹配,这些对象分别失去了哪些优化能力。
Configuration Analyzer 的作用其实就是在 R8 已经拿到完整程序图以后做这件事,官方把结果归纳成三个最重要的指标:
- Shrinking Score
- Optimization Score
- Obfuscation Score

这些分数表达的都是"当前代码中有多少比例仍然允许 R8 做相应操作" ,比如 :
- Optimization Score 为 66%,意思就是当前约有 66% 的 classes、fields 和 methods 还可以接受 R8 的优化,剩下约 34% 因配置约束无法参与相应优化,R8 这里的 optimization 包括 method inlining、class merging 之类这些会直接影响 App 运行结构的处理。
- Shrinking Score 衡量的是 R8 可以进行 unused code elimination 的范围。
- Obfuscation Score 反映类、字段和方法有多少还允许重命名。
这三个分数可以让过去很模糊的 ProGuard 编程可量化的数据,比如一次依赖升级之后:
erlang
Optimization Score 82% → 61%
Shrinking Score 91% → 73%
Obfuscation Score 95% → 94%
这还是就可以直接判断,问题主要出现在 shrinking 和 optimization,不是 obfuscation,接下来再从 Analyzer 里追踪影响最大的 keep rules,这样比在整个项目里搜索 -keep 效率高得多。
而且更重要的是,Configuration Analyzer 分析的是最终汇总到应用上的配置,也就是第三方 library 提供的 consumer keep rules 同样会进入这个分析过程。
Google 特别替代,library 作者通常不知道宿主 App 的具体使用方式,因此 consumer rules 有时会写得比较保守,甚至限制 library 之外的应用代码,Analyzer 可以显示这些规则的来源,并分析所有合并后的 consumer rules 对应用造成的影响。
对,说的就是我,我的 SDK rule 就是很广泛,觉得不是因为我想偷懒,我为的是广大开发者可以更灵活。
实际上这对于大型项目来说还挺重要的,因为性能问题一般可能不在 app/proguard-rules.pro 中,你检查自己项目的文件可能觉得很干净,真正影响数千个 method 的规则其实藏在某个 AAR 里。
另外一个就是 Blast Radius ,这个玩意是 Google 在 r8-analyzer 的内部数据结构的概念,Analyzer 生成的数据里包含 keep_rule_blast_radius_table, 每条规则下面继续记录 class_blast_radius、field_blast_radius 和 method_blast_radius,然后同时还有 kept_by、keep constraint、文件来源以及 Maven 坐标等信息。
换句话说,R8 不只告诉你 "这条 rule 很宽",它实际上建立了 "哪条 rule 限制了哪些 App 元素" 的关系 ,比如一条 xxxxxxxxxx -keep class com.example.** { *; } ,最终可以被转换成更有工程价值的信息:
yaml
这条规则影响:
Classes: 214
Fields: 863
Methods: 1732
对应约束:
DONT_OPTIMIZE
DONT_SHRINK
DONT_OBFUSCATE
来源:
某个具体 proguard 文件 / library
r8-analyzer Skill 自带的分析脚本就是直接读取这些数据,它会遍历 kept_class_info_table、kept_field_info_table 和 kept_method_info_table,然后再通过每个对象的 kept_by 关联到 keep rule,根据 DONT_OPTIMIZE、DONT_OBFUSCATE 和 DONT_SHRINK 统计受到限制的对象数量。
以当前 build 中 live class、live field、live method 的总量作为分母,计算三项分数。
然后按照规则库,R8 就告诉你 "package wildcard 风险较高",Configuration Analyzer 可以知道这一条规则在当前这个真实构建里究竟命中了什么,以及产生了多大的实际约束范围。
Google 的 Skill 还保留了一套启发式危险程度规则,只有拿不到 quantitative data 时才会用,比如 package-wide wildcard 被放在最高优先级,! inversion、整类成员 wildcard 也被列为高影响写法。
简单来说就是 Google 自己也区分了两种分析:
- 有编译器数据时看真实 Blast Radius
- 旧项目不支持生成这些数据时,才退回基于语法和经验的检查
然后 Configuration Analyzer 还专门分析 subsumed rules ,比如项目同时存在:
java
-keep class com.example.package.** { *; }
-keep class com.example.package.User
这里第二条规则从配置文件本身看没有错误,甚至可能非常精确,但由于第一条已经覆盖整个 package,第二条的效果实际上已经完全包含在第一条里面。
这种情况在历史很长的 Android 项目中非常常见,不同团队、不同 library、不同年代分别增加规则,最终配置中会出现大量重叠。
Configuration Analyzer 也可以显式建立这种 subsumption 关系,同时显示哪条规则覆盖了另一条。
Google 官方给出的处理方法也是,先识别真正通过 reflection 等动态机制访问的 class、field 和 method,然后比较宽规则与窄规则的影响范围。
如果窄规则已经完整描述真实需求,就可以处理范围过大的那一条,完成修改以后在重新生成 Analyzer 报告,用 Release Build 做测试。
这里有一个边界很重要:Configuration Analyzer 能告诉你规则限制了什么,但不能替你证明某个对象在运行时一定不需要 keep。
R8 面对 Class.forName()、getDeclaredField()、JNI、序列化框架、基于 annotation 的动态扫描的情况,不支持只依靠常规静态调用图推导全部关系,所以 Analyzer 的数据解决的是"影响范围有多大",真正决定能否删规则时,还是要回到程序语义。
而且现在 AGP 9.3 之后,Configuration Analyzer 已经成为一个独立的开发循环,AGP 9.3 开始提供独立 Gradle Task:
ruby
./gradlew :app:analyzeReleaseR8Config
新的 standalone task 可以不需要完整生成 APK 或 App Bundle,可以直接分析配置变化,官方也明确把它作为本地反复调试 keep rules 时的推荐方式。HTML 报告默认输出到:
arduino
app/build/reports/r8/r8-config-analyzer-release.html
完整执行 assembleRelease 等 R8 Release Build 时也会自动生成 Analyzer 报告,默认位置是:
arduino
build/outputs/mapping/release/configanalyzer.html
而对于 r8-analyzer Skill 来说,实际上是把整套流程写成了 SOP,当前版本首先检查 build.gradle、build.gradle.kts、gradle.properties 和 libs.versions.toml,确定 AGP/R8 版本,然后选择三条执行路径。
- AGP 9.3 以上直接运行
./gradlew :app:analyzeReleaseR8Config,随后读取生成的 protobuf,通过 Skill 自带脚本转成 JSON,再运行分析脚本生成analysis_result.txt - 如果 AGP 低于 9.3,但 R8 已经达到 9.3.7-dev,那就通过 R8 的
dumpkeepradiustodirectory输出原始 Blast Radius protobuf,之后同样进入 JSON 和定量分析流程,Google 在 reference 文件里甚至已经把 protobuf schema、转换脚本和分析代码都准备好了 - 只有当项目连支持 Configuration Analyzer 的 R8 都没有时,Skill 才进入 heuristic path,手工检查
proguard-rules.pro,根据 Google 提供的 keep-rule impact hierarchy 和 reflection guide 做判断
所以总的来收,R8 Configuration Analyzer 解决"哪条 Keep Rule 到底限制了多少真实代码",r8-analyzer Skill 解决让 Coding Agent 按一套可靠流程,把这些编译器数据变成可以处理的工程结论。
这个功能实际上真的非常不错,约等于白给,因为直接让 AI 处理就行。