Gradle transform api 简介

前言

在打包流程中,我们知道生成.class文件后,利用dx工具生成.dex文件,而利用Transform API可以在生成.class文件后修改.class文件,从而修改源码。我们将Transform注册到AppExtension中,在java compile Task执行后会执行Tramsform类型的task。
具体过程参考以下两篇文章

  • Android Gradle Plugin 源码解析(上)
  • Android Gradle Plugin 源码解析(下)

Transform API

根据transform api官网中的介绍,可以知道gradle从1.5.0-beta1开始,支持第三方插件修改class文件。transform api的目的是为了简化自定义类的注入,使得我们不需要写task。

注册

@Override
void apply(Project project) {
    ……
    def android = project.extensions.getByType(AppExtension)
    android.registerTransform(theTransform)
}

transform 抽象类

自定义一个Transform时,需要继承Transform,下面看下几个抽象方法和transform方法。

public abstract class Transform {

    //返回自己Transform类的名字
    public abstract String getName();

    //传入transform类型,class文件或者resource(非res下文件, 而是assests内的资源),也可以多个。
    //类型必须是接口QualifiedContent中的DefaultContentType枚举类里的值
    //TransformManager中定义了一些,如TransformManager.CONTENT_CLASS
    public abstract Set getInputTypes();

    //传入transform文件的所属范围,可以多个。TransformManager中定义了一些,如TransformManager.SCOPE_FULL_PROJECT
    //类型必须是接口QualifiedContent中的枚举类Scope里的值
    public abstract Set getScopes();

    //是否是增量编译
    public abstract boolean isIncremental();

    //主要执行方法
    public void transform(TransformInvocation transformInvocation);

    ……
}

transform中的TransformInvocation是主要处理的对下,根据api文档,

//中是传过来的输入流,其中有两种格式,一种是jar包格式一种是目录格式。
transformInvocation.getInputs() 
//获取到输出目录,最后将修改的文件复制到输出目录,这一步必须做不然编译会报错
transformInvocation.getOutputProvider() 

常用的写法如下

@Override
void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException,
        IOException {
    super.transform(transformInvocation)

    Collection inputs = transformInvocation.getInputs()
    TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()

    if (!isIncremental() && outputProvider != null) {
        //非增量编译,需要删除之前的输出
        outputProvider.deleteAll()
    }

    inputs.each { TransformInput input ->
        //遍历directoryInputs
        input.directoryInputs.each { DirectoryInput directoryInput ->
            // todo 注入代码……
            // 获取output目录
            def dest = outputProvider.getContentLocation(directoryInput.name,
                    directoryInput.contentTypes, directoryInput.scopes,
                    Format.DIRECTORY)
            // 将input的目录复制到output指定目录
            FileUtils.copyDirectory(directoryInput.file, dest)
        }
        //遍历jarInputs
        input.jarInputs.each { JarInput jarInput ->
            //todo 注入代码……
            //生成输出路径
            def dest = outputProvider.getContentLocation(jarName + md5Name,
                    jarInput.contentTypes, jarInput.scopes, Format.JAR)
            //将输入内容复制到输出
            FileUtils.copyFile(jarInput.file, dest)
        }
    }
}

可以看到上面代码中有进行了遍历,但是注入代码需要Javassist或者ASM等来处理。可以看下一篇

参考 :
android动态编译技术:Plugin Transform Javassist

你可能感兴趣的:(Gradle transform api 简介)