背景

在 kotlin 编译中,CompileKotlinTask 会拿到所有变动的输入,并且对变动的输入进行对应的编译。在一定程度上,kotlin 编译的 compile avoidance 已经做得相当不错了,但是还是会存在一些 badcase。

今天我们的主角是 bad case 之一:R.jar 的变动导致 kotlin 任务全量编译

在读本篇文章之前,可以先了解一下

Why

为什么 R.jar 的变动会让 kotlin fallback 到全量编译呢?

我们可以看一下 changesDetectionUtils 的代码。

Untitled

Kotlin 会去 gradle 输入的 InputChanges 里面找到变动 & 删除的文件,并且去 classpathSet 中去查找里面是否有 inputchanges 相关的变动。

而 classpathSet 中,除了 android.jar、kotlin 等这些不怎么会变化的 jar 外,另外两个可能会经常变动的 jar 分别是

也就是说,如果这俩个 jar 被删了的话,会直接全量编译,当然这种情况非常少。

如果发生变动的话,kotlin 会去调用 historyFilesFotChangedFiles(modifiedClasspath),来找到变动的 classpath 的「DirtySymbol」,对于 classed.jar kotlin 有自己的处理方式(详见 kotlin 增量编译策略 ),然而对于 R.jar,kotlin 就无能为力了。

也就是说 R.jar 只要发生了变动,一定会触发 kotlin 的全量编译。

但是资源的增删、改名都会引起 R.jar 的变动呀,那也就是说只要资源的变动就会触发 kotlin 的全量编译啦❓❓❓

确实是。

如果看过 关于 R 的一切 ,我们可以知道,在 AGP 的较高版本中,为了纯 kotlin 工程不启动 javaCompile,agp 把原来的 R.java 都改成了 R.jar,当然他们的内容是一样的。