What is Gradle

Gradle is an open source tool for automating project building based on Apache Ant and Apache Maven concepts. It uses a Groovy-based domain-specific language (DSL) to declare project Settings, and now adds a Kotlin-based DSL based on the Kotlin language, ditching all the tedious XML-based configuration. Mainly for Java applications. It currently supports C++, Java, Groovy, Kotlin, Scala, and Swift, and plans to support more languages in the future.

Gradle is a tool for building projects. If you know anything about Ant or Maven, Gradle is a tool for building projects. There are many steps required to package an Android project into an APK file (dependency, packaging, deployment, signing, distribution, differential management of various channels…..) Grdle is one such tool for managing the packaging process. So Gradle is not a language, it’s just a tool that can do its job in many languages.

I met Gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { Dependencies jcenter repositories {Google () ()} {the classpath 'com. Android. View the build: gradle: 4.0.1' / / NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }Copy the code

This is the build.gradle file under the project that we created automatically when we created the Android project

At first glance, the content structure will look like a configuration file, which is quite different from the Java way of writing it, but if you rewrite it, it will be easier to understand.

Dependencies ({classpath 'com. Android. View the build: gradle: 4.0.1'})Copy the code

If you’re familiar with Kotlin, you’ll recognize that as Lambda, right? Exactly. Grovy’s syntax, called a Closure, works much like Lambda in that its core purpose is to pass a method (or function).

void method(Closure closure){
  ...
}

method ({
  println("execute closure")
})
Copy the code

This is Grovy’s closure definition syntax. If the closure is the last argument to a method, you can omit the parentheses, just like the default build.gradle file content. We know that these are not configurations, but are written like configurations. Buildscript {}, Repositories {}, and so on are all method calls, and we can see how these methods are defined.

/** * Configures the repositories for the script dependencies. Executes the given closure against the {@link * RepositoryHandler} for this handler. The {@link RepositoryHandler} is passed to the closure as the closure's * delegate.  * * @param configureClosure the closure to use to configure the repositories. */ void repositories(Closure configureClosure); /** * Configures the repositories for the script dependencies. Executes the given closure against the {@link * RepositoryHandler} for this handler. The {@link RepositoryHandler} is passed to the closure as the closure's * delegate.  * * @param configureClosure the closure to use to configure the repositories. */ void repositories(Closure configureClosure);Copy the code

You can see the syntax is the same, but, in fact, there are some exceptions, such as:

The classpath 'com. Android. Tools. Build: gradle: 4.0.1'Copy the code

The classPath here is not the same as the other methods. This is actually a Grovy mechanism called methodMissing, where when a method is called and no method is found, the method is called methodMissing() and the logic is handled within that method. There is not much introduction about methodMissing. If you are interested, you can go to know about it.

About buildTypes

BuildTypes has two methods, debug and release, by default, but you can actually customize them with arbitrary names, such as Testing

buildTypes {
    internal {
        //TODO
    }
    debug {
        //TODO
    }
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
}
Copy the code

As you can see from the default buildTypes methods debug and release, this is generally used to distinguish between production and test builds. We can perform at compile time gradle assembleInternal assembleDebug/assembleRelease command, and executing those commands execute buildTypes not just under the three methods, If there are internal/debug/release directories in the SRC directory, the corresponding directories are also packaged into the project. For example, the main and internal directories under SRC are packaged when assembleInternal is executed. We can use this feature to customize different versions of the app.

api,impementation,compileOnly

  • The API is exactly the same as compile, passing dependencies, that is, dependencies from child modules are carried to the main module
  • Implementation does not pass dependencies and only applies to the current Module
  • CompileOnly is valid only at compile time and does not participate in packaging

gradle wrapper

Gradlew will download the gradle version from gradle-wrapper.properties

Task

Let’s look at a piece of Gradle code

println(rootProject.buildDir)

task clean(type: Delete) {
  delete rootProject.buildDir
}
Copy the code

Then execute./gradlew

> Configure project :
D:\work******\build
Copy the code

You can see the directory where build is printed

Let’s write it another way. Let’s try it again

task clean(type: Delete) {
  println(rootProject.buildDir)
  delete rootProject.buildDir
}
Copy the code

/gradlew I did not execute a clean task, so I should not print it.

> Configure project :
D:\work******\build
Copy the code

What? What the hell? Can I execute the code in a task without executing it? But why wasn’t the build directory deleted? This is so weird!!

I’m sure most of you will look at this and wonder, can a method only execute a few lines? This is not the case. The code in Clean Task is actually executed, but when it comes to delete, it is put into the task list, and the delete logic is actually executed after the clean call. We can think of the work added to the task list as a configuration operation, and the real execution operation is when clean is called.

One might look at this and think, what if I want to output a prompt log after the task has finished executing? If the log is executed at the end of the task, it is definitely not output after the task is executed. So what do we do? The doLast doFirst method can be used to print the log at execution time

task clean(type: Delete) {println(1) Delete rootproject. buildDir println(2) doLast {println "finish"} doFirst {println "start"}} > Configure project: 1 2 > Task :clean Start Execution completeCopy the code

The output logs also show that task execution has two phases: configuration and execution.

Task calls other tasks using denpendsOn

task taskA(){
  doLast{
    println"taskA executed"
  }
}

task taskB(dependsOn:taskA){
  doLast {
    println "taskB executed"
  }
}
Copy the code

This means that taskB is executed before taskA, and if taskA has dependencies, taskA’s dependencies are executed first, and so on recursively. This is a network of dependencies called a directed acyclic graph.

Gradle executes the process

  • setting.gradle
  • Directed acyclic graphs are drawn at the configuration stage of each build.gradle
  • Execution phase

gradle plugin

A simple custom plugin

class TestPlugin implements Plugin<Project> {

    @Override
    void apply(Project target) {
        println "Hello gradle plugin"
    }
}

apply plugin: TestPlugin
Copy the code

This way we can see “Hello gradle Plugin “when executing./gradlew

> Configure project :app
Hello gradle plugin
Copy the code

gradle plugin-extension

class TestPlugin implements Plugin<Project> {
    @Override
    void apply(Project target) {
        def extension = target.extensions.create("testPluginExt11",TestPluginExtension)
        target.afterEvaluate {
            println "Hello gradle ${extension.name}"
        }
    }
}

class TestPluginExtension{
    def name = 'pluginExt'
}

apply plugin: TestPlugin

testPluginExt11{
    name = 'newPluginExt'
}
Copy the code
Configure project :app Hello gradle newPluginExtCopy the code

Create plug-in project

  • Library name can only be used with buildSrc, because buildSrc is the plug-in’s reserved Module name
  • BuildSrc Module cannot be configured to setting.gradle
  • Configure fixed meta-info /resouces/ MEata-INF /gradlep-lugin/**.properties
 implementation-class=***.***.***
Copy the code

Transform