
相信大家最近应该都知道目前 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-analyzerSkill把 Configuration Analyzer 的运行、数据转换、结果分析和报告生成整理成了一套可以交给 Coding Agent 执行的流程。那 Configuration Analyzer 到底分析了什么R8 的 keep rule 本质上是在给优化器增加约束比如-keep class com.example.feature.** { *; }从文本上看这条规则是保留某个 package 下面的类和成员但对于性能优化来说问题是当前这个 Release Build 里到底有多少 class、field、method 被它匹配这些对象分别失去了哪些优化能力。Configuration Analyzer 的作用其实就是在 R8 已经拿到完整程序图以后做这件事官方把结果归纳成三个最重要的指标Shrinking ScoreOptimization ScoreObfuscation 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 编程可量化的数据比如一次依赖升级之后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.** { *; }最终可以被转换成更有工程价值的信息这条规则影响 Classes: 214 Fields: 863 Methods: 1732 对应约束 DONT_OPTIMIZE DONT_SHRINK DONT_OBFUSCATE 来源 某个具体 proguard 文件 / libraryr8-analyzerSkill 自带的分析脚本就是直接读取这些数据它会遍历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比如项目同时存在-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./gradlew :app:analyzeReleaseR8Config新的 standalone task 可以不需要完整生成 APK 或 App Bundle可以直接分析配置变化官方也明确把它作为本地反复调试 keep rules 时的推荐方式。HTML 报告默认输出到app/build/reports/r8/r8-config-analyzer-release.html完整执行assembleRelease等 R8 Release Build 时也会自动生成 Analyzer 报告默认位置是build/outputs/mapping/release/configanalyzer.html而对于r8-analyzerSkill 来说实际上是把整套流程写成了 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-analyzerSkill 解决让 Coding Agent 按一套可靠流程把这些编译器数据变成可以处理的工程结论。这个功能实际上真的非常不错约等于白给因为直接让 AI 处理就行。