前面介绍了如何开发一个gradle插件,那么这次将分享一下如何进行插桩。
关于Transform的介绍和用法网上介绍的比较多,我就不再重复写了。我理解的就是Gradle在1.5以后提供了一个Transfrom API,允许用户在编译的过程中再去修改字节码。而Transfrom相当于是一个字节码的过滤器,有一个TransfromManager对他们进行管理,从一个Transfrom流入,然后对字节码进行加工处理以后再输出,然后流入下一个Transfrom,直到所有的Transfrom过滤处理完成。
那么我们的Transfrom就需要注册到TransfromManager中去。
首先第一步就是创建一个Transfrom,创建的方式就是继承一个抽象类Transform。关于该抽象类里面的其他方法的介绍,网上也有很多资料来参考,我主要介绍一下处理字节码的方法transform()
public abstract void transform(
@NonNull Context context,
@NonNull Collection<TransformInput> inputs,
@NonNull Collection<TransformInput> referencedInputs,
@Nullable TransformOutputProvider outputProvider,
boolean isIncremental) throws IOException, TransformException, InterruptedException;
Transform的inputs有两种类型,一种是目录,一种是jar包,要分开遍历
println("注册的Transform执行了")
// 分开对Jar和目录进行遍历
inputs.each { TransformInput input ->
//对类型为“文件夹”的input进行遍历
input.directoryInputs.each { DirectoryInput directoryInput ->
//文件夹里面包含的是我们手写的类以及R.class、BuildConfig.class以及R$XXX.class等
//我们要在.class文件里插桩就在这里操作
[......插入处理字节码文件的代码]
// 获取output目录
def dest = outputProvider.getContentLocation(directoryInput.name,
directoryInput.contentTypes, directoryInput.scopes,
Format.DIRECTORY)
// 将input的目录复制到output指定目录
FileUtils.copyDirectory(directoryInput.file, dest)
}
//对类型为jar文件的input进行遍历
input.jarInputs.each { JarInput jarInput ->
//jar文件一般是第三方依赖库jar文件
// 重命名输出文件(同目录copyFile会冲突)
def jarName = jarInput.name
def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
if (jarName.endsWith(".jar")) {
jarName = jarName.substring(0, jarName.length() - 4)
}
//生成输出路径
def dest = outputProvider.getContentLocation(jarName + md5Name,
jarInput.contentTypes, jarInput.scopes, Format.JAR)
//将输入内容复制到输出
FileUtils.copyFile(jarInput.file, dest)
}
}
从input处理完file后一定要对外进行输出。
注意:
这里使用到了apache-common包,我们需要引入一下不然会报错
compile "commons-io:commons-io:+"
compile 'commons-codec:commons-codec:+'
(这两个包在gradle里引入uri我也是找了好久才找到的。。。。目前我们这里的Transform相当于什么也没有做,然后将file再原封不动的输出了。
写好Transform以后我们就需要对Transform进行注册,注册的方式呢就是在我们的Plugin类里,还是那个void apply(Project project) 方法中
System.out.println("------------------注册了Transform----------------------");
def android = project.extensions.findByType(AppExtension)
android.registerTransform(new ShujuliTransform(project))
然后我们上传后,再去刷新我们使用插件的项目。这个时候就需要打包的时候才能执行Transform。
对项目进行Clean Project,然后刷新Gradle,再Build Apks
我们在Gradle打控制台看到我们打印的那段信息,说明我们成功注册了我们的Transform