R8 / Android Gradle 插件是否足够智能以保持库 classes/methods 只在测试 apk 中需要?

Is R8 / Android Gradle Plugin smart enough to keep library classes/methods needed only in test apk?

假设我有一个依赖库的应用程序。这个库有两种方法:

在我调用的应用程序中 usedInApp()。我还有一个调用 usedInTest() 的仪器测试。如果我 运行 仪器测试 ./gradlew app:connectedDebugAndroidTest 是 R8/AGP 足够聪明知道要保留 usedInTest() 还是会被删除?

由于应用程序未使用 usedInTest,R8 会将其删除,并且当 运行 测试您的测试时,它将失败并显示 MethodNotFouldError。所以你需要一个保留规则来确保 usedInTest 在测试时仍然在应用程序中。一种好方法是添加注释,例如KeepForTesting 并在应用程序中注释测试需要什么。然后添加此保留规则:

-keep,allowobfuscation class * {
  @KeepForTesting *;
}

注意 allowobfuscation 修饰符。这允许将这些测试方法重命名为更短的名称。当 Android Studio 构建测试时,它会自动添加 -applymapping 选项以及构建应用程序时生成的映射文件。这样,在测试中对 usedInTest 的引用将在 运行ning R8 之后重命名为应用程序中的实际方法。

对于 R8 本身,我们通过分析 R8 测试来找到 R8 的哪些部分未在 public API 上用于测试,从而实现了自动化。从中我们综合保持规则来保持这一点。然后我们可以在 R8 上 运行 R8,然后 运行 在该版本的 R8 上进行所有测试——这也是我们最终发布的版本。