Gradle_06 Gradle Plugin

500 阅读1分钟

之前写过一篇Gradle_05 自定义插件,这篇算是复习吧

编写gradle插件的目的就是把逻辑独立的代码抽取和封装

基本使用

1.现在,我们在app/build.gradle下添加如下代码,

  • dshPlugin是我们自己编写的一个插件
  • dshExtension是一个扩展,我们可以创建一个别名为dshE的扩展
  • 执行.gradlew命令,输出「Hello 大欢安卓gradle扩展插件」
    apply plugin:dshPlugin
    
    //自定义插件
    class dshPlugin implements Plugin<Project>{
        @Override
        void apply(Project target) {
            def extension = target.extensions.create('dshE',dshExtension)
            println("Hello ${extension.name}")
        }
    }
    
    class dshExtension{
        def name = '大欢安卓gradle扩展插件'
    }
    

2.上面我们使用了别名,如果想要修改name的值,name我们可以使用别名dshE的一个闭包

dshE{
    name 'dsh_gradle'
    //等价于方法调用 -> name('dsh_gradle')->setName('dsh_gradle')
}
  • 但是这样并不会输出修改后的值,我们需要在afterEvaluate也就是task执行完之后才能输出
class dshPlugin implements Plugin<Project>{

    @Override
    void apply(Project target) {
        def extension = target.extensions.create('dshE',dshExtension)
        println("Hello ${extension.name}")//修改前:大欢安卓gradle扩展插件

        target.afterEvaluate {
            println("Hello ${extension.name}")//修改后:Hello修改后:dsh_gradle
        }
    }
}

3.至此,我们完成了一个简单插件的编写,但是这样在我们的gradle文件中编写显然很笨拙,我们的目的是只需要一行apply代码apply plugin:dshPlugin就能够方便地使用和配置插件,所以我们要换一种方式,编写能够方便使用的插件

自定义插件

在项目中新建buildSrc目录,这是安卓插件的默认目录,目录结构像这样 2

  • resources/META-INF/gradle-plugins/*.properties 中的 * 是插 件的名称,例如 *.properties 是com.dshPlugin.properties ,最终在应用插件是的代码就 应该是:
    • apply plugin: 'com.dshPlugin'
  • *.properties 中只有一行,格式是:
    • implementation-class=com.dsh.plugin.DshPlugin
    • 其中等号右边指定了 Plugin 具体是哪个类
  • Plugin 和 Extension 写法和在 build.gradle 里的写法一样 关于 buildSrc 目录
    • 这是 gradle 的一个特殊目录,这个目录的 build.gradle 会自动被执行,即 使不配置进 settings.gradle。(实际上在 gradle 的 6.0 之后, buildSrc 已经成为了一个保留字,你在 settings.gradle 里配置的项目已经不允 许叫 buildSrc )
    • buildSrc 所配置出来的 Plugin 会被自动添加到编译过程中的每一个 project 的 classpath,因此它们才可以直接使用 apply plugin: 'xxx' 的方 式来便捷应用这些 plugin

这样写的代码运行结果与在build.gradle中编写的效果是一致的

Transform

  • 是什么:是由 Android 提供了,在项目构建过程中把编译后的文件(jar 文件和 class 文件)添加自定义的中间处理过程的工具
  • 怎么写
    • 先加上依赖:buildSrc/build.gradle
      repositories {
        google()
        jcenter()
      }
      
      dependencies {
          implementation 'com.android.tools.build:gradle:3.5.4'
      }
      
      sourceCompatibility = "1.7"
      targetCompatibility = "1.7"
      
    • 然后继承 com.android.build.api.transform.Transform ,创建 一个子类:
      class DshTransform extends Transform {
        @Override
        String getName() {
          return 'dshTransform'
        }
      
        @Override
        Set<QualifiedContent.ContentType> getInputTypes() {
          return TransformManager.CONTENT_CLASS
        }
      
        @Override
        Set<? super QualifiedContent.Scope> getScopes() {
          return TransformManager.SCOPE_FULL_PROJECT
        }
      
        @Override
        boolean isIncremental() {
          return false
        }
      
        @Override
        void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
          def inputs = transformInvocation.inputs
          def outputProvider = transformInvocation.outputProvider
          inputs.each {
            it.jarInputs.each {
              File dest = outputProvider.getContentLocation(it.name, it.contentTypes, it.scopes, Format.JAR)
              println "Jar: ${it.file}, Dest: ${dest}"
              FileUtils.copyFile(it.file, dest)
            }
            it.directoryInputs.each {
              File dest = outputProvider.getContentLocation(it.name, it.contentTypes, it.scopes, Format.DIRECTORY)
              println "Dir: ${it.file}, Dest: ${dest}"
              FileUtils.copyDirectory(it.file, dest)
            }
          }
        }
      }
      
      
    • 还能做什么:修改字节码 上面的这段代码只是把编译完的内容原封不动搬 运到目标位置,没有实际用处。要修改字节码,需要引入其他工具,例如 javassist。 javassist 的使用教程在网上有很多,可以搜索一下。