美文网首页
Gradle Plugin插件编写以及 bulidSrc 的使用

Gradle Plugin插件编写以及 bulidSrc 的使用

作者: 蜗牛是不是牛 | 来源:发表于2022-11-18 17:30 被阅读0次

Plugin基本的写法

在 build.gradle 下

class PluginDemo implements Plugin<Project> {

    @Override
    void apply(Project project) {
        println 'hi !!!'
    }

}

apply plugin: PluginDemo

Terminal 窗口执行 ./gradlew 得到如下结果



Extension

同样在 build.gradle 下

class ExtensionDemo {
    def extensionName = 'test'
}

总体代码:

class PluginDemo implements Plugin<Project> {

    @Override
    void apply(Project project) {
        def extension = project.extensions.create('testExtension',
                ExtensionDemo)
       println "hi ${extension.extensionName}!"
    }

}

class ExtensionDemo {
    def extensionName = 'test'
}

apply plugin: PluginDemo

执行 ./gradlew 得出结果



[图片上传中...(image.png-da99a8-1668735711594-0)]
这时就可以在gradle文件下引用 testExtension 了

// 在project.extensions.create()方法中注册了testExtension这个扩展
// 这段代码在apply plugin: PluginDemo后面
testExtension {
    extensionName 'new test'
}

这时候执行,会发现在 Terminal 窗口里打印的依然是 hi test! 而不是 hi new test!

这是因为代码执行顺序问题,赋予新的值的时候已经执行完println,所以无法打印hi new test!

只需要加上afterEvaluate{}便可:

def extension = project.extensions.create('testExtension',
                ExtensionDemo)
// 表示在最后执行
project.afterEvaluate {
    println "hi ${extension.extensionName}!"
}

插件写在 buildSrc 下

如果每一个插件都像上述这种写法,必然会无法管理和难读(假设项目要定义起码三个插件)
所以插件应该写在 buildSrc 下

插件的本质:把逻辑独立的代码抽取和封装

关于buildSrc目录

● 这是 gradle 的一个特殊目录,这个目录的 build.gradle 会自动被执行,即使不配置进 settings.gradle。(实际上在 gradle 的 6.0 之后, buildSrc 已经成为了一个保留字,你在 settings.gradle 里配置的项目已经不允许叫 buildSrc )

● buildSrc 所配置出来的 Plugin 会被自动添加到编译过程中的每一个 project 的 classpath,因此它们才可以直接使用 apply plugin: 'xxx' 的方式来便捷应用这些 plugin

在项目新建一个 Module 取名为 bulidSrc
新建后一般会报错 'buildSrc' cannot be used as a project name as it is a reserved name
需要在 settings.gradke里把 include ':buildSrc'去掉即可


  1. 把之前写的 PluginDemo 和 ExtensionDemo 写在 bulidSrc 下
  2. 在 main 目录下新建 *.properties 文件
  3. 把 main 下的 java 目录改成 groovy

如图:



resources/META-INF/gradle-plugins/*.properties 中的 * 是插件的名称,例如 *.properties 是 com.tongsr.plugindemo.properties ,最终在应用插件是的代码就应该是:

apply plugin: 'com.tongsr.plugindemo'

testExtension {
    extensionName 'new test~'
}

*.properties 中只有一行,格式是:

implementation-class=com.tongsr.buildsrc.PluginDemo

● Plugin 和 Extension 写法和在 build.gradle 里的写法一样

运行结果:


Transform

● 是什么:是由 Android 提供了,在项目构建过程中把编译后的文件(jar 文件和 class 文件)添加自定义的中间处理过程的工具

● 怎么写
○ 先加上依赖

// 因为 buildSrc 需要自己添加仓库
repositories {
    google()
    jcenter()
}

dependencies {
    implementation 'com.android.tools.build:gradle:7.0.4'
}

然后继承 com.android.build.api.transform.Transform ,创建 一个子类:

class TransformDemo extends Transform {

    // 构造方法
    TransformDemo() {

    }

    // 对应的 task 名 @Override
    String getName() {
        return 'tongsrTransform'
    }

    // 你要对那些类型的结果进行转换(是字节码还是资源文件?)
    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    // 适用范围包括什么(整个 project 还是别的什么?)
    @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 {
            // jarInputs:各个依赖所编译成的 jar 文件
            it.jarInputs.each {
                // dest: /app/build/intermediates/transforms/tongsrTransform/ ...
                File dest = outputProvider.getContentLocation(it.name, it.contentTypes,
                        it.scopes, Format.JAR)
                FileUtils.copyFile(it.file, dest)
            }
            // derectoryInputs:本地 project 编译成的多个 class 文件存放的目录
            it.directoryInputs.each {
                // dest: /app/build/intermediates/transforms/tongsrTransform/ ...
                File dest = outputProvider.getContentLocation(it.name, it.contentTypes,
                        it.scopes, Format.DIRECTORY)
                FileUtils.copyDirectory(it.file, dest)
            }
        }
    }

}

○ 还能做什么:修改字节码 上面的这段代码只是把编译完的内容原封不动搬运到目标位置,没有实际用处。要修改字节码,需要引入其他工具,例如 javassist。 javassist 的使用教程在网上有很多,可以搜索一下

用buildSrc管理项目版本

目的:管理项目第三方SDK以及Module之间的版本号等

  1. 新建一个 buildSrc,和前文叙述无差别
  2. 把 build.gradle 改成 build.gradle.kts
  3. 在 java 目录下新建一个 Dependencies 类
object Libs {
    const val CORE = "androidx.core:core-ktx:1.7.0"
}

object Version {
    const val MIN_SDK = 21
}

4.Sync项目后,在 app 的 build.gradle 引用定义好的 Libs 和 Version,这里做个简单示例

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.tongsr.mytest"
        minSdk Version.MIN_SDK // 注意这里
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
}

dependencies {
    implementation Libs.CORE // 注意这里
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

用Kotlin DSL构建Android项目

同样也是利用 buildSrc 来管理项目,不同的点是用 Kotlin DSL 代替 Groovy

把所有的 .gradle 文件换成 .kts 文件。把 Groovy 的语法换成 Kotlin 语法

来自:https://www.yuque.com/tongsr/xy0i84/hmgn81

相关文章

网友评论

      本文标题:Gradle Plugin插件编写以及 bulidSrc 的使用

      本文链接:https://www.haomeiwen.com/subject/wtvpxdtx.html