Gradle插件系列(二)—— 配置自己的Transform

1,211 阅读2分钟

0 此系列文章

在上一篇,我们已经知道了如何创建一个简单的插件,这一节将在此基础上继续说说如何配置自己的Transform

1 转换器 Transform

转换器Transform是由Google提供,让开发者可以在编译后,打包前这段时期,进行额外干预操作,从而提供操作字节码的时机。

2 创建 Transform

创建自定义的FreeCoderTransform类,然后继承至Transform

public class FreeCoderTransform extends Transform {
    // 1
    @Override
    public String getName() { 
        return "freecoder";
    }

    // 2
    @Override
    public Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS;
    }

    // 3
    @Override
    public Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT;
    }

    // 4
    @Override
    public boolean isIncremental() {
        return false;
    }

    // 5
    @Override
    public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        Collection<TransformInput> inputs = transformInvocation.getInputs();
        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();

        inputs.forEach(transformInput -> {
            transformInput.getJarInputs().forEach(jarInput -> {
                File dest = outputProvider.getContentLocation(jarInput.getName(), jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR);
                try {
                    FileUtils.copyFile(jarInput.getFile(), dest);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            transformInput.getDirectoryInputs().forEach(directoryInput -> {
                File dest = outputProvider.getContentLocation(directoryInput.getName(), directoryInput.getContentTypes(), directoryInput.getScopes(), Format.DIRECTORY);
                try {
                    FileUtils.copyFile(directoryInput.getFile(), dest);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        });
    }
}

标记1处:对应自定义TransformTask名称,同步完成后,会显示在Gradle控制面板上,比如:transformClassesWithXXXForDebug

标记2、3处:定义了我们将要操作的编译过程中具体哪些类型的文件,其中 2 的类型:

CONTENT_CLASS://class 文件

CONTENT_JARS: //jar包,包括class文件与resource资源文件

CONTENT_RESOURCES // resource资源文件

CONTENT_NATIVE_LIBS // 本地libs

CONTENT_DEX // dex文件

CONTENT_DEX_WITH_RESOURCES // dex文件与resource资源文件

标记 3 处:表示作用的项目范围,SCOPE_FULL_PROJECT表示整个项目。

标记 4 处:表示是否支持增量编译。

标记 5 处:这里是个核心方法,需要覆盖重写,并且按Google提供的输出目录outputProvider上输出,否则将这个Transform引入会报错。

transformInvocation.getInputs()获取编译后的所有class文件,transformInvocation.getOutputProvider()获取Google提供的输出目录,我们把这些编译后的文件做完处理后,然后再扔向该目录,最终参与到打dex包的过程。

而后就是简单的复制工作,至于处理,我们下一节讲,这个过程可以实现面向切面的编程。

3 引入 Transform

如下:(接上一节代码)


public class FreeCoderPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        final FreeCoderExtension extension = project.getExtensions()
                .create("freecoder", FreeCoderExtension.class);
        project.afterEvaluate(innerProject -> System.out.println("extension: " + extension.name));

        // 创建转换器
        FreeCoderTransform freeCoder = new FreeCoderTransform();
        // 1
        BaseExtension baseExtension = project.getExtensions().getByType(BaseExtension.class);
        // 2
        baseExtension.registerTransform(freeCoder);
    }
}

标记1处:BaseExtension指的就是Android打包过程中,com.android.application这个插件所包含的扩展,方便开发者在打包过程中进行相应的干预。

标记2处:把我们的Transform注册进入该扩展中。

到此为止,我们就配置好了自己的Transform,下一节,就来讲讲如果通过更改字节码达到面向切面编程的效果。