美文网首页
Gradle基础到进阶——Gradle基础自定义插件(三)

Gradle基础到进阶——Gradle基础自定义插件(三)

作者: Peakmain | 来源:发表于2021-09-18 14:31 被阅读0次

    环境配置

    • 官方地址:https://gradle.org/releases/
    • 下载之后将gradle下面的bin目录添加到系统的Path中(Android studio目录一般都是在.gradle目录下)


      image.png
    • 测试是否配置好:gradle -v

    Hello Gradle

    • 新建一个build.gradle
    println("Hello Gradle")
    
    • cmd定位到新建文件目录下
    gradle help
    
    • 查看输出结果


      image.png
    • build.gradle是构建Project的核心文件,也是入口:
      • 如果没有该文件,会出现not found in root project 'xxxxx' 提示异常。
      • 必须要有一个可以运行的task,运行后自动生成.gradle文件夹下的内容

    gradle wrapper

    • Gradle Wrapper用来配置开发过程中用到的Gradle构建工具版本。避免因为Gradle不统一带来的不必要的问题
    • 在工程目录下使用cmd命令生成wrapper:
    gradle wrapper
    
    • 标准的gradle工程目录
      • gradlew和gradlew.bat分别是Linux和Windows下的可执行脚本
      • 具体业务逻辑是在/gradle/wrapper/gradle-wrapper.jar中实现
      • gradlew最终还是使用Java执行这个jar包来执行相关的Gradle操作


        image.png

    gradle-wrapper.properties

    image.png
    • distributionBase:下载的Gradle压缩包解压后存储的主目录
    • distributionPath:相对于distributionBase的解压后的Gradle压缩包的路径
    • distributionUrl:Gradle发行版压缩包的下载地址
      • bin:二进制发布版。
      • all:bin基础上还包含了源码和文档。
    • zipStoreBase:同distributionBase,只不过存放的是zip压缩包的
    • zipStorePath:同distributionPath,只不过存放的是zip压缩包的

    gradle构建机制

    android gradle工程目录

    image.png
    Gradle DSL
    • DSL(Domain Specific Language) 领域特定语言,或领域专属语言。简单来说就是专门关注某一领域的语言,它在于专而不是全,最典型的比如HTML。
    • Gradle可以使用Groovy DSL,专门用来开发Gradle的构建脚本。所以说Gradle整体设计是以作为一种语言为导向的,并非成为一个严格死板的框架

    settings.gradle

    image.png
    • Gradle支持多工程构建,使用settings.gradle来配置添加子工程(模块)。
    • settings文件在初始化阶段执行,创建Settings对象,在执行脚本时调用该对象的方法。
    • Settings.include(String... projectPaths):
      • 将给定的目录添加到项目构建中,':app'表示文件相对路径,相当于'./app'文件夹。
      • 多项目架构进行分层,把同层次的子工程放在同一文件夹下便于管理,使用':xxx:yyy'表示

    build.gradle

    • build.gradle是项目构建文件,每个工程都有一个build.gradle文件。
    • build.gradle在配置阶段执行,并创建相应工程的Project对象,执行的代码可以直接调用该对象提供的方法或属性

    Daemon(守护进程)

    • 项目启动时,会开启一个client,然后启动一个daemon,通过client向daemon收发请求,项目关闭,client关闭,daemon保持启动,有类似项目再次部署时,会直接通过新的client访问已经启动的daemon,所以速度很快,默认daemon不使用3小时后关闭;不同项目兼容性考虑,也可使用--no-daemon 启动项目,就没有速度优势了
    • 手动停止daemon:gradle wrapper --stop

    生命周期

    • Initialization
      • Gradle支持单项目和多项目构建。在初始化阶段,Gradle确定哪些项目参与构建,并为每个项目创建project实例,比如解析setting.gradle
    • Configuration
      • 配置阶段,解析每个工程的build.gradle文件,创建要执行的任务子集和确定各种任务之间的关系,并对任务做一些初始化配置
      • 解析过程中并不会执行各个build.gradle中的task
      • 经过Configration阶段,Project之间及内部Task之间的关系就确定了
      • 一个Project包含很多Task,每个Task之间有依赖关系。Configuration会建立一个有向图来描述Task之间的依赖关系
      • 所有Project配置完成后,会有一个回调project.afterEvaluate(),表示所有的模块都已经配置完了
    • Execution
      • 运行阶段,Gradle根据配置阶段创建和配置要执行的任务子集,执行任务

    执行流程

    image.png

    自定义任务

    task

    • task是gradle中最小的任务单元,任务之间可以进行复杂的操作(如动态创建任务,多任务间依赖调用等等)。gradle的执行其实就是由各种任务组合执行,来对项目进行构建的
    • gradlew tasks -all命令查看所有任务
    • gradlew A B 命令表示执行任务A和B

    自定义任务

    • build.gradle中自定义任务
      • task(任务名){}


        image.png
    • { }执行的是配置阶段的代码,执行阶段要处理的逻辑需要调用doFirst、doLast方法,在闭包中实现。
      • doFirst{}表示任务执行开始时调用的方法
      • doLast{}表示任务执行结束调用的方法。
    • task A(dependsOn:[B]){} 表示任务A依赖于任务B,那么B执行在A之前。
    task A {
        println("Hello A")
        doLast {
            println("doLast A")
        }
    }
    task B {
        println("Hello B")
        doLast {
            println("doLast B")
        }
    }
    
    task test(dependsOn: [A, B]) {
        doLast {
            println("doLast test")
        }
    }
    A.dependsOn(B)
    
    • 自定义的任务默认分组到other中。

    DefaultTask

    • task定义的任务其实就是DefaultTask的一种具体实现类的对象。
    • 可以使用自定义类继承DeaflutTask:
      • 在方法上使用@TaskAction注解,表示任务运行时调用的方法。
      • 使用@Input表示对任务的输入参数。
      • 使用@OutputFile表示任务输出文件。
      • 使用inputs,outputs直接设置任务输入/输出项。
      • 一个任务的输出项可以作为另一个任务的输入项 (隐式依赖关系)。

    获取任务的类型

    task A {
    
    }
    println(A.class)//class org.gradle.api.DefaultTask_Decorated
    

    自定义任务类型实现自定义任务

    • 创建一个自定义任务


      image.png
    • 自定义任务实现文件的输入输出
    class MyTask extends DefaultTask {
    
        String from
        File out
    
        @TaskAction
        void method() {
            println "我是自定义任务"
            //文件进行操作
            println inputs.files.singleFile
            def inFile = inputs.files.singleFile
             //将build.gradle文件复制到test文件
            def outFile = outputs.files.singleFile
            outFile.createNewFile()
            outFile.text = inFile.text
        }
    }
    
    task myTask(type: MyTask) {
        from = "I am Peakmain"
        out = file("test.txt")
        inputs.file file('build.gradle')
        outputs.file file('test.txt')
    }
    

    细心的人可能会发现,我们执行多次的时候并没有打印,这是因为我们的内容没有改变,所以会直接跳过@TaskAction方法,如果我们想每次都执行TaskAction怎么解决,我们可以在构造函数中添加一行代码

        MyTask() {
            outputs.upToDateWhen {
                false
            }
        }
    

    钩子函数

    初始化阶段
    android中的settings.gradle中主要是gradle的初始化,具体大家看上面Gradle执行流程图

    gradle.projectsLoaded {
        println "gradle.projectsLoaded"
    }
    gradle.settingsEvaluated {
        println "gradle.settingsEvaluated"
    }
    

    Terminal中执行命令:gradlew help,我们便可以看到我们的打印


    image.png

    配置阶段
    gradle对项目所有library生效,project只对当前library生效

    gradle.beforeProject {
        println "gradle.beforeProject"
    }
    
    gradle.afterProject {
        println "gradle.afterProject"
    }
     //所有配置完成之后执行
    gradle.taskGraph.whenReady {
        println "gradle.taskGraph.whenReady"
    }
    //只对当前有效
    project.beforeEvaluate {
     //root无效
        println "beforeEvaluate"
    }
    project.afterEvaluate {
        println "afterEvaluate"
    }
    

    结果


    image.png

    gradle设置监听

    //为gradle设置监听
    gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
        @Override
        void beforeEvaluate(Project project) {
            println "beforeEvaluate"
        }
    
        @Override
        void afterEvaluate(Project project, ProjectState projectState) {
            println "afterEvaluate"
        }
    })
    //设置构建监听
    gradle.addBuildListener(new BuildListener(){
    
        @Override
        void buildStarted(Gradle gradle) {
    
        }
    
        @Override
        void settingsEvaluated(Settings settings) {
    
        }
    
        @Override
        void projectsLoaded(Gradle gradle) {
    
        }
    
        @Override
        void projectsEvaluated(Gradle gradle) {
    
        }
    
        @Override
        void buildFinished(BuildResult buildResult) {
    
        }
    })
    

    Project

    • build.gradle在配置阶段会生成project实例,在build.gradle中直接调用方法或属性,实则是调用当前工程的project对象的方法或属性
    • 使用Project提供的api,更方便在多项目构建设置
      • project(":app"){}指定的project(这里是app)配置
      • allprojects{}所有的project配置
      • subprojects{}所有的子project 配置
      • buildscript{}此项目配置构建脚本类路径
    image.png

    属性扩展

    • 使用ext对任意对象属性进行扩展
      • 对project进行使用ext进行属性扩展,对所有子project可见
      • 一般在root project进行ext属性扩展,为子工程提供复用属性,通过rootProject直接访问
      • 任意对象都可以使用ext来添加属性:使用闭包,在闭包定义扩展属性。直接使用=赋值,添加扩展属性
      • 由谁进行ext调用,就属于谁的扩展属性
      • 在build.gradle中,默认当前工程的project对象,所以在build.gradle直接使用"ext="或者"ext{}"其实就是给project定义扩展属性
    • 使用gradle.properties以键值对形式定义属性,所有project可直接使用
    ext{//相当于project.ext
        author="peakmain"
    }
    task myTask{
    }
    myTask.ext.username="peakmain"
    println(myTask.ext.username)
    println(myTask.username)
    

    Gradle插件

    脚本插件

    afterEvaluate {
        println tasks.getByName("packageDebug")
        task zip(type: Zip) {
            archiveName "outputs.zip"// 输出的文件名字
            destinationDir file("${buildDir}/custom")// 输出的文件存放的文件夹
            from tasks.getByName("packageDebug").outputs.files// 输入的文件
            tasks.getByName("packageDebug").outputs.files.each {
                println it
            }
        }
    }
    

    二进制插件

    class MyTask implements Plugin<Project>{
    
        @Override
        void apply(Project project) {
                println("MyTask")
        }
    }
    apply plugin:MyTask
    

    自定义Gradle插件,实现packageDebug的打包

    1.新建buildSrc目录
    2.新建一个build.gradle,同步构建一下
    3.新建文件夹src/main/java
    4.build.gradle引入插件

    apply plugin:"java"
    

    5.新建PeakmainPlugin.java类

    public class PeakmainPlugin implements Plugin<Project> {
        @Override
        public void apply(Project project) {
            project.afterEvaluate(it -> {
                System.out.println(it.getTasks().getByName("packageDebug"));
                Map<String, Class<?>> typeMap = new HashMap<>();
                typeMap.put("type", Zip.class);
                Zip zipTask = (Zip) project.task(typeMap, "zipDebug");
                zipTask.setArchiveName("outputs.zip");
                zipTask.setDestinationDir(new File(project.getBuildDir().getAbsolutePath() + "/custom"));
                zipTask.from(it.getTasks().getByName("packageDebug").getOutputs().getFiles());
            });
        }
    }
    

    6.app目录下的build.gradle引入插件,同步一下

    apply plugin:PeakmainPlugin
    

    7.AndroidStudio右边的Gradle的Other多了一个zipDebug


    image.png

    8.结果


    image.png

    相关文章

      网友评论

          本文标题:Gradle基础到进阶——Gradle基础自定义插件(三)

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