返回

不要再使用Transform来处理字节码了!一个hook AGP源码导致的错误

Android

Transform 弊端

在上一篇文章《总听说AGP,它到底做了什么?》中,我们分析了 AGP(Android Gradle Plugin) 做了哪些事,了解到 AGP 就是为打包这个过程服务的。那么,本篇文章就和大家聊一聊 Transform。

Transform 是 AGP 提供的一个用来处理字节码的工具。我们可以通过实现 Transform 接口,然后在其中处理字节码。

但是,使用 Transform 来处理字节码也有很多弊端:

  • 性能开销大: Transform 会在编译过程中执行,这会增加编译时间。
  • 难以调试: Transform 的代码是在编译过程中执行的,这使得调试 Transform 的代码非常困难。
  • 易出错: Transform 的代码是直接操作字节码的,这很容易出错。

Hook AGP 源码

为了解决 Transform 的这些弊端,我们可以通过 hook AGP 源码来实现同样的功能。

AGP 源码是一个非常庞大的项目,但是我们可以通过一些工具来帮助我们找到我们需要修改的地方。

例如,我们可以使用 grep 命令来搜索 AGP 源码中包含特定字符串的地方。

找到我们需要修改的地方之后,我们就可以修改 AGP 源码了。

示例

下面是一个使用 hook AGP 源码来解决 Transform 导致的问题的示例。

我们想要实现的功能是,在编译过程中将所有的 R.java 文件合并成一个 R.java 文件。

我们可以通过 hook AGP 源码中的 com.android.build.gradle.tasks.MergeResources 类来实现这个功能。

MergeResources 类的 mergeRFiles() 方法中,我们可以找到以下代码:

for (RFile rf : rFiles) {
  ...
}

这段代码是用来合并所有的 R.java 文件的。

我们可以将这段代码修改为以下代码:

List<RFile> rFiles = new ArrayList<>();
for (RFile rf : rFiles) {
  ...
  rFiles.add(rf);
}

RFile mergedRFile = new RFile(outputDir, "R.java");
FileWriter fw = new FileWriter(mergedRFile);
for (RFile rf : rFiles) {
  ...
  fw.write(rf.getContents());
}
fw.close();

这段代码的作用是,将所有的 R.java 文件合并成一个 R.java 文件。

总结

通过 hook AGP 源码,我们可以实现一些原本无法实现的功能。但是,hook AGP 源码也有很多风险,我们需要慎重考虑是否要 hook AGP 源码。