Gradle插件的使用

Gradle

Android Studio 项目是使用 Gradle 构建的,构建工具 Gradle 可以看做是一个脚本,包含一系列的Task,依次执行这些 Task 后,项目就打包成功了。而 Task 有一个重要的概念,那就是inputs 和outputs 。
Task 通过 inputs 拿到一些东西,处理完毕之后就输出 outputs ,而下一个 Task 的 inputs 则是上一个 Task 的outputs。
不同的 Plugin 提供了不同的 Task 来实际不同的功能。

可以简单的理解为: Gradle只是一个框架,真正起作用的是plugin。而plugin的主要作用是往Gradle脚本中添加Task

我们需要在整个 Gradle 工作的过程中,找到合适的时机来插入自定义的 Plugin,然后在 Plugin 中使用 Javassist 对字节进行操作 ,所以使用 Javassit 的前提是掌握自定义 Gradle 插件。

从Gradle1.5.0-beta1开始,android的gradle插件引入了Transform,我们刚好就可以利用这个 API 来使用 Javassist 。

Javassist

Javassist 是一个执行字节码操作的库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深入的了解。
Javassist 可以绕过编译,直接操作字节码,从而实现代码注入,所以使用 Javassist 的时机就是在构建工具 Gradle 将源文件编译成 .class 文件之后,在将 .class 打包成 dex 文件之前。

开发步骤:

1、创建自定义 Gradle plugin module
新建Android library module 留下src/main和build.gradle,其他的文件删除

2、在 插件的module 中添加依赖:

apply plugin: 'groovy'
apply plugin: 'maven'

dependencies {
    compile gradleApi()
    compile localGroovy()
    compile fileTree(dir: 'libs', includes: ['*.jar'])

    compile 'com.android.tools.build:transform-api:1.5.0'
    compile 'javassist:javassist:3.12.1.GA'
    compile 'commons-io:commons-io:2.5'
    compile 'com.android.tools.build:gradle:3.4.2'
}

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: 'file:///Users/xxx/Maven/transform-lib/')
        }
    }
}

group = 'com.xxx.transform'
version = '1.0.0'

3、Gradle Transform API
在main目录下创建 groovy 文件夹,然后在 groovy 目录下就可以创建我们的包名和 groovy 文件了,记得后缀要已 .groovy 结尾。在这个文件中引入创建的包名,然后写一个Class继承于Plugin< Project > 并重写apply方法,并注册Transform:

public class MyPlugin implements Plugin<Project> {

    void apply(Project project) {
        //AppExtension就是build.gradle中android{...}这一块
        def android = project.extensions.getByType(AppExtension)

        //todo 注册一个Transform
        def classTransform = new MyClassTransform(project)
        android.registerTransform(classTransform)
    }

4、配置plugin
在main目录下创建resources文件夹,继续在resources下创建META-INF文件夹,在META-INF文件夹下创建gradle-plugins文件夹。

5、gradle-plugins文件夹下创建一个xxx.properties文件,
注意:这个xxx就是在app下的build.gradle中引入时的名字,例如:apply plugin: ‘xxx’。
在文件中写 implementation-class=com.xxx.plugin.MyPlugin

6、修改build.gradle 内容,然后执行 uploadArchives 这个task 上传到 maven 库,就将我们的这个插件打包上传到了本地 maven 中,可以去本地的 maven 库中查看

7、自定义 Transform

public class MyClassTransform extends Transform {

    private static final NAME = "MyClassTransform"

    public MyClassTransform(Project project) {
        MyInjector.init(project)
    }

    /**
     * Transform的名称
     * */
    @Override
    public String getName() {
        return NAME
    }

    /**
     * 需要处理的数据类型,有两种枚举类型
     * */
    @Override
    public Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    /**
     * 指定操作范围,官方文档有其中范围
     * */
    @Override
    public Set<QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    /**
     * 是否支持增量编译
     * */
    @Override
    public boolean isIncremental() {
        return false
    }

    /**
     * 核心方法,文件输入、输出流,在这一步做注入操作
     * */
    @Override
    public void transform(Context context,
                          Collection<TransformInput> inputs,
                          Collection<TransformInput> referencedInputs,
                          TransformOutputProvider outputProvider,
                          boolean isIncremental) throws IOException, TransformException, InterruptedException {
          //使用javasist动态注入带代码
    }
}

项目中使用

1、添加Maven仓库源,在工程的build.gradle中如下添加:

buildscript {
    repositories {
        //...
        maven {
            url 'file:///Users/xxx/Maven/transform-lib/'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.2'
        classpath 'com.xxx.transform:plugin:1.0.0'
    }
}

2、app中引入,在app的build.gradle目录下如下添加:

apply plugin: 'com.gerile.transform'

3、到此已经结束了gradle插件的创建及引用了,后续的就只是对class或xml文件的修改了,根据项目的需求插入或修改代码,具体实现请查看javasist的api。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容