Following on from the previous Gradle Automation Project Building Tutorial, we will continue our in-depth study of Gradle Automation project building techniques.

Gradle concept

What is gradle Wrapper?

Gradle wrapper is a gradlew script that gradle generates for us. It contains gradlew version information. Gradle wrapper is a gradlew script that gradle generates for us. It automatically downloads gradle Dist and gradle Wrappers to the code management system so that no developer has to mess with gradle versions.

Run the gradle command./ on Linux: gradlew build. Generate all the output and perform all the checks. Gradlew run. Generate the application and execute some script or binary gradlew check. Perform all test tasks such as Tests, Linting, gradlew Clean. Delete the build file directory. Gradlew projects. View the project structure. Gradlew tasks. View the task list. Gradle Help --task someTask gradlew Dependencies View the dependency list. Gradlew assembleDebug (or gradlew aD) compile and Debug packages gradlew assembleRelease (or gradlew aR) compile and Release packages gradlew -? - h, -- help. View help information. Gradlew -v - version. View the version information. Gradlew -s - stacktrace. The stack information is printed when the task is executed. For example, gradle build --s: -q, --quiet. Only the errors class information is printed. -i - info. Print detailed information. Performance class: --configure-on-demand,--no-configure-on-demand Whether to enable the on-demand configuration mode. - build - cache, - no - build - the cache. Whether to use caching. Others see its official documents: https://docs.gradle.org/current/userguide/command_line_interface.htmlCopy the code

Gradle executes the process

  1. Initialization phase: Execute settings.gradle script to parse all projects in the whole Project and build Project objects corresponding to all projects.
  2. Configuration phase: parse all tasks in the project object and construct the topology of all tasks
  3. Execution phase: Execute specific tasks and dependent tasks

Gradle life cycle

// settings.gradle file println 'initialization stage is completed' // settings.gradle is called after configuration. Gradle. SettingsEvaluated {println "Settings: Perform settingsEvaluated..." Gradle. projectsLoaded {println "Settings: Execute projectsLoaded..."} // Called when all projects imported from settings.gradle are created. } child project must be set in root project to take effect. Root project must be set in settings.gradle to take effect gradle.beforeProject {proj -> println "Settings: ${proj.name} beforeProject"} // Call gradle.afterProject {proj -> println "Settings after each project configuration: ${proj.name} afterProject"} // After all project configurations are complete, call gradle.projectsEvaluated {println "Settings: Perform projectsEvaluated..." } // Before building starts, call gradle.buildStarted {println "Build starts..." } // call gradle.buildFinished {println "buildFinished..." } // build.gradle file /** * configure the listener callback before the Project phase starts */ this.beforeEvaluate {println 'Before the configuration phase executes'} /** * Configure the callback after the Project phase finishes * / enclosing afterEvaluate {println ' 'configuration phase has been completed} / * * * gradle this Project after the completion of the callback to monitor * / this. Gradle. BuildFinished {println } /** * when all project configurations are complete, Gradle. projectsEvaluated {gradle -> println "All projects are configured. To generate a Task dependencies "} / * * * said the Project "Task dependencies have been generated" * / gradle. TaskGraph. WhenReady {TaskExecutionGraph graph - > println "Task dependencies have been generated"} / * * * each of task execution before the callback * / gradle. TaskGraph. BeforeTask {task task - > println "Project [${task. The Project. The name}] - > task [${task. The name}] before execution to be callback"} / * * * after each task execution is callback * / gradle. TaskGraph. AfterTask { Task, TaskState TaskState -> // Println "Project[${task.project.name}]-- > task [${task.name}] To bounce about: to bounce about. To bounce about: to bounce about,skipped: to bounce about,executed:${taskstate-executed},didWork:${tas kState.didWork}]" }Copy the code
  • Note 1: There are duplicate gradle life cycles in setting.gradle and build.gradle
  • Note 2: Some life cycles are valid only in setting.gradle, such as settingsEvaluated
  • Note 3: According to the Gradle execution process, the first step is to initialize the setting. Gradle file, and the second step is to configure each project. Projects are configured in the order of the first letters of the projectName a-Z, so if a lifecycle is declared in the middle of all projects, it will have an effect on the declaration and subsequent projects.

Attached is a graphic illustration of the execution process and declaration cycle of the unknown boss:

Project

Peoject definition:

1. From the perspective of Gradle, Gradle manages in a tree structure. The outermost layer is the root project and the inner module is a sub-project. 2. Each sub-project will have corresponding output, such as: APK, WAR, AAR, etc. Build. gradle files are also used to determine whether a project is configured or not. 4. Gradle manages modules in a tree structure. You can create modules in inner modules, but in practice you will never create sub-projects in a sub-project. Note: You can verify the tree structure of a Project by using the command gradlew projectsCopy the code

The Project related API

GetSubProjects () getSubProjects() getSubProjects() getSubProjects() getSubProjects() getSubProjects() getSubProjects() getSubProjects() getSubProjects() getSubProjects() GetParent () gets the parent project of the current project (if called in rooProject build.gradle, Closure configureClosure = Closure configureClosure (String Path, Closure configureClosure); Allprojects (Closure configureClosure) configures all the projects of the current Project and its sub-project through Closure configureClosure Subprojects (Closure configureClosure) Configures all the projects of the subproject (excluding the current project).Copy the code

Attribute dependent API

  1. Use ext block extension properties in gradle script files.

    // rootProject : Build. Gradle ext {/ / define extension attributes compileSdkVersion = 28 libAndroidDesign = 'com. Android. Support: design: 28.0.0'} / / app: Build. gradle android {compileSdkVersion = this.pilesdkVersion // Property in parent project, child project can be accessed directly using... } dependencies {the compile this. LibAndroidDesign / / can also use: enclosing rootProject. LibAndroidDesign... }Copy the code
  2. Extend the properties in the gradle.properties file

    // gradle.properties isLoadTest=true // mCompileSdkVersion=28 // setting. Gradle // Determine whether Test Module needs to be imported  if(hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) { include ':Test' } // app : build.gradle android { compileSdkVersion = mCompileSdkVersion.toInteger() ... }Copy the code
    1. HasProperty (‘ XXX ‘) : Checks if XXX properties are defined in gradle.properties.
    2. Properties defined in gradle.properties can be accessed directly, but the resulting property is of type Object, which is usually converted by the toXXX() method.

File related API

GetBuildDir () gets the build directory of the current project (each project has its own build directory) getProjectDir() Gets the current project directory File File (Object path) to locate a File, relative to the current project began to find ConfigurableFileCollection files (Object... Paths) locate multiple files, similar to Closure Closure copy(Closure Closure) fileTree(Object baseDir, Closure configureClosure) locate a file tree (directory + file), File tree traversal examples: Println getContent('common.gradle') def getContent(String path){try{def file = file(path) return file.text }catch(GradleException e){ println 'file not found.. '} return null} / / copy files and folder copy {the from file (' build/outputs/apk) into getRootProject () getBuildDir () path + '/ apk/' Outputs outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ /outputs/ Visit {FileTreeElement Element -> println 'The file name is: '+element.file.name copy { from element.file into getRootProject().getBuildDir().path + '/test/' } } }Copy the code

Dependency apis

1. Configure the project warehouse and gradle plugin dependencies

// rootProject : Build. Gradle buildscript {ScriptHandler ScriptHandler - > / / configure project warehouse address ScriptHandler. Repositories {RepositoryHandler repositoryHandler -> repositoryHandler.jcenter() repositoryHandler.mavenCentral() repositoryHandler.mavenLocal() repositoryHandler.ivy {} repositoryHandler.maven { MavenArtifactRepository mavenArtifactRepository -> mavenArtifactRepository.name 'personal' mavenArtifactRepository.url 'http://localhost:8081/nexus/repositories/' MavenArtifactRepository. Credentials {username = 'admin' password = 'admin123'}}} / / configure project "plug-in" (write gradle script to use third-party libraries) depend on the address ScriptHandler. Dependencies {classpath 'com. Android. View the build: gradle: 2.2.2' classpath 'com. Tencent. Tinker - patch - gradle - plugin: 1.7.7'}} / / = = = = = = = = = = = = = = = = = = = = = = = = = = = the simplified = = = = = = = = = = = = = = = = = = = = = = = = = = = = Since the delegate in the repositoryHandler closure is repositoryHandler, we can omit the repositoryHandler reference and use its properties and methods directly. */ repositories { jcenter() mavenCentral() mavenLocal() ivy {} maven { name 'personal' url 'http://localhost:8081/nexus/repositories/' credentials { username = 'admin' password = 'admin123' } } } // Allocation of project "plug-in" (write gradle script to use third-party libraries) rely on address dependencies {classpath 'com. Android. View the build: gradle: 2.2.2' classpath 'com. Tencent. Tinker - patch - gradle - plugin: 1.7.7'}}Copy the code

2. Configure third-party library dependencies for applications

// app : build.gradle dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // compile file() // compile file() // compile files() // compile files() // compile files() // compile files() // compile files() // compile files() // compile files( 'com. Android. Support: appcompat - v7:28.0.0' / / rely on third-party libraries in the warehouse (i.e., the remote library) implementation project (' CommonSDK ') {/ / rely on engineering under other Module (i.e., // Exclude module: 'support-v4' // exclude module: 'com.android.support' // To exclude dependencies: // Disable module transitive false } implementation(' XXX ') {changing true // pull from the server every time} // compile inside the stack Provided (' com. Tencent. Tinker: tinker - android - anno: 1.9.1 ')}Copy the code
  1. Implementation and API: Compile the dependency packages and package the classes in the dependency packages into APK.
  2. Provided: Provides compilation support only, but the classes in the dependency package do not write to APK when packaged.
    1. Dependency packages are only useful at compile time. (For example, Tinker’s Tinker-Android-anno is only used to generate Application at compile time, and there is no need to package the classes in this library into APK, which can reduce the size of APK package)
    2. The dependent project already has the same version of the third-party library, so you can use Provided to avoid double references.

External command API

// copyApk task: Task ('copyApk') {// doLast executes doLast {// Gradle executes def sourcePath = this.buildDir.path + '/outputs/apk' def destinationPath = '/Users/xxx/Downloads' def command = "mv -f ${sourcePath} ${destinationPath}" // exec block code is basically fixed exec {try {executable 'bash' args '-c', command println 'the command is executed success.' }catch (GradleException e){ println 'the command is executed failed.' }}}}Copy the code

Task

Task definition and configuration

The Task definition method is very simple and can be created in two main ways: * An iterative way to declare the Task and doLast,doFirst method to add executable code; * One is to create a task quickly with “<<” and execute the task code in a closed manner. But it’s not limited to these two.

TaskContainer: Manages all tasks, such as adding and searching tasks.

  1. Define (create) tasks

    // Create task helloTask {println 'I am helloTask.'} // create task this.tasks.create(name: 'helloTask2') { println 'i am helloTask 2.' }Copy the code
    • To view all tasks, run gradlew Task
    • Run the gradlew taskName command
  2. Configure the Task

    Task helloTask(group: 'study', description: 'Task study'){// } task helloTask {group 'study' // or setGroup('study') description 'task study' // or setDescription('task study')... }Copy the code

    Task can be configured with group, description, name, Type, dependsOn, Overwrite, and Action.

    • Note 1: After a Task is grouped, it is placed in a specific group for easy grouping and searching. (Grouped into other by default)
    • Note 2: Adding a description to a Task is equivalent to adding a comment to a method.

Task execution details

Gradle’s execution phase is all about tasks. Only Tasks can be executed in the execution phase.

  1. Use doFirst and doLast in Task:
    Println 'I am helloTask.' doFirst {println 'the task group is: '+ group} // doFirst {}} // 2. DoFirst {println 'The task description is: hellotask.dofirst {println' The task description is: Def startBuildTime, def startBuildTime, EndBuildTime this.afterevaluate {Project Project -> // Find the specified Task by taskName def preBuildTask = Project.tasks. getByName('preBuild') // The first Task to be executed // executes prebuildTask.dofirst {startBuildTime = System.currentTimemillis ()} def before the preBuildTask is executed BuildTask = project.tasks.getByName('build') Run buildTask.dolast {endBuildTime = System.currentTimemillis () println "the build time is: ${endBuildTime - startBuildTime}" } }Copy the code
  2. conclusion
    1. Code written directly in the Task closure is executed during the configuration phase. The code logic can be put into the execution phase through doFirst, doLast blocks.
    2. Multiple doFirst and doLast can be specified.
    3. Externally specified doFirst and doLast are executed before internally specified ones.
    4. DoFirst and doLast can extend existing tasks provided with Gradle.

The execution order of tasks

  1. Task execution order can be specified in three ways:
    1. A: dependsOn
    2. Specified via Task input/output (equivalent to the first)
    3. The order of execution is specified through the API
  2. The Task dependency
    Task taskX {doLast {println 'taskX'}} task taskY {doLast {println 'taskY'}} task taskX {doLast {println 'taskX'}} task taskY {doLast {println 'taskY'}} Task taskZ(dependsOn: taskY) // Task taskZ(dependsOn: taskY) DependsOn (taskX, taskY) {doLast {println 'taskZ'}} $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) $dependsOn(taskX, taskY) Task taskZ() {dependsOn this.tasks.findall {return task.name.startswith ('lib')} DoLast {println 'taskZ'}} task lib1 << {println 'lib1'} task lib2 << {println 'lib2'} task lib3 << { Println 'lib3'} println 'lib3'} note: << is to create a task quickly, the code in the closure is the same as in the doLast closure, but this method has been marked as deprecatedCopy the code
    • TaskZ relies on taskX and taskY, so when executing taskZ, taskX and taskY are executed first.
    • TaskZ relies on taskX and taskY, but taskX has nothing to do with taskY, and their execution order is random.
  3. Input and output of Task

Process: Task Inputs –> Task One –> Task Outputs –> Task Inputs –> Task Outputs –>….. Inputs and outputs are attributes of a Task. Inputs can be arbitrary datatype objects, while outputs can only be files (or folders). 3. Outputs of TaskA can be used as TaskB inputs. // Example: Save each version information to the specified release.xml

Ext {versionCode = '1.0.0' versionName = '100' versionInfo = 'first version of App, 'destFile = file('release.xml') if (destFile! = null && ! Destfile.exists ()) {destfile.createnewFile ()}} // writeTask input extended attributes, Outputs task writeTask {// Specify inputs for task elsions. property('versionCode', this.versioncode) elsions. property('versionName', this.versionName) inputs.property('versionInfo', VersionInfo) // specify output for task elsion.file this.destfile doLast {def data = elsions.getProperties () // return a map file Elsion.getfiles ().getsingleFile () def versionMsg = new versionMsg (data) def sw = new StringWriter() def xmlBuilder = new groovy.xml.MarkupBuilder(sw) if (file.text ! = null && file.text.size() <= 0) {// There is no content in the file // Actually, XmlBuilder writes XML data to sw xmlBuilder.releases {// < Releases > child of releases {// < Releases > VersionCode (versionmsg.versioncode) // The child of <release> <versionCode>1.0.0<versionCode> versionName(versionmsg.versionName) VersionInfo (versionmsg.versioninfo)}} file.withwriter {writer -> writer.append(sw.toString())}} Xmlbuilder.release {versionCode(versionmsg.versionCode) versionName(versionmsg.versionName) versionInfo(versionMsg.versionInfo) } def lines = file.readLines() def lengths = lines.size() - 1 file.withWriter { writer -> lines.eachWithIndex { String line, int index -> if (index ! = lengths) { writer.append(line + '\r\n') } else if (index == lengths) { writer.append(sw.toString() + '\r\n') Writer. append(line + '\r\n')}}}}}} // readTask Output file for input writeTask task readTask {inputs. File destFile doLast {def file = inputs.files.singleFile println file.text } } task taskTest(dependsOn: [writeTask, ReadTask]) {doLast {println 'Task completed'}} class VersionMsg {String versionCode String versionName String versionInfo} After executing gradle taskTask, you can see the release.xml file in the project directory.Copy the code
  1. The Task API specifies the order
    • MustRunAfter: Specifies that one or more tasks must be executed before they are executed.
    • ShouldRunAfter: Same as mustRunAfter, but not mandatory.
    task taskX {
        doLast {
            println 'taskX'
        }
    }
    task taskY {
        // shouldRunAfter taskX
        mustRunAfter taskX
        doLast {
            println 'taskY'
        }
    }
    task taskZ {
        mustRunAfter taskY
        doLast {
            println 'taskZ'
        }
    }
    Copy the code

    After executing gradle taskY taskZ taskX, you can see that the terminal is still executed in taskX, taskY, taskZ order.

  2. Hang to the build lifecycle
    1. Example: After the build task is completed, execute a custom task
      this.afterEvaluate { Project project ->
          def buildTask = project.tasks.getByName('build')
          if (buildTask == null) throw GradleException('the build task is not found')
          buildTask.doLast {
              taskZ.execute()
          }
      }
      Copy the code
    2. Example: Tinker inserts the custom manifestTask into the Gradle script between the processManifest and processResources tasks
      TinkerManifestTask manifestTask = project.tasks.create("tinkerProcess${variantName}Manifest", TinkerManifestTask)
      ...
      manifestTask.mustRunAfter variantOutput.processManifest
      variantOutput.processResources.dependsOn manifestTask
      Copy the code
  3. Task type
    1. Gradle DSL Version 5.1
    2. Copy-gradle DSL Version 5.1–> Task types

Gradle other modules

Settings class

Settings. gradle (settings. Java) determines which projects need to be processed by Gradle and takes up about one-third of gradle’s life cycle, the Initialzation phase.

SourceSet class

Gradle has a convention directory structure in the same format as Maven. Gradle’s directory structure can be changed. Change the default file location so that Gradle knows which resources to look for in which folders.

JniLibs. SrcDirs = ['libs']}} sourceSets {main SrcDirs = [' SRC /main/res', // common resource directory 'SRC /main/res-ad', // advertising resource directory 'SRC /main/res-player'] // Player-related resource directory}}} // 2. SourceSets jniLibs.srcDirs = ['libs'] res.srcDirs = ['src/main/res', 'src/main/res-ad', 'src/main/res-player'] } } } // 3. Using the idea of programming, SourceSets this.android. SourceSets {main {jniLibs. SrcDirs = ['libs'] res.srcDirs = [' SRC /main/res', 'src/main/res-ad', 'src/main/res-player'] } }Copy the code

Gradle Plugin

What is a Gradle Plugin?

Plugin in Gradle is the embodiment of Task encapsulation to complete a specified function. As long as the project depends on a Plugin, it can execute all functions of the Plugin. For example, using Java plug-in, you can print jar package, and using Android plug-in, you can generate APK and AAR.

A custom Plugin

  1. Create plug-in project
    • Create the buildSrc folder in the project directory.
    • In the buildSrc directory, create the SRC folder, build. Gradle file.
    • In the buildSrc/ SRC directory, create the main folder.
    • Under buildSrc/ SRC /main, create groovy and Resources folders, respectively.
    • In buildSrc/SRC/main/resources to create a meta-inf folder, create a gradle again under the meta-inf – plugins folder.
    • Enter the following script in the build.gradel file:
      apply plugin: 'groovy'
      
      sourceSets {
          main {
              groovy {
                  srcDir 'src/main/groovy'
              }
              resources {
                  srcDir 'src/main/resources'
              }
          }
      }
      Copy the code

      Finally, Async projects and buildSrc is identified, as shown in the following figure: E: CodeProject android Github JcyDemoList SourceCodeAnalysis SRC Gradle custom plugin.png

  2. Create a plug-in class:

Like Java, in groovy directory, create a package, create a plug-in class (such as: com. Android. Gradle. GradleStudyPlugin), the plug-in class must implement the Plugin interface. Plugin import org.gradle.api.Plugin import org.gradle.api.project

/** * GradleStudyPlugin implements Plugin<Project> {/** ** param Project implements Plugin<Project> */ @override void apply(project project) {println 'hello gradle study plugin. + project.name } } ```Copy the code
  1. Specify plug-in entry:

After writing the logic for the plug-in class, you need to create a properties file in the meta-info.gradle-plugins directory. Com. Android. Gradle. Properties), in the plug-in class declaration in the properties, in order to specify the plugin entrance. > The name of the properties file will be used as the basis for the current Gradle plug-in to be referenced by the APP project. Implementation – class = com. Android. Gradle. GradleStudyPlugin / / if the error Could not find implementation class ‘XXX’, // implementation-class=GradleStudyPlugin // implementation-class=GradleStudyPlugin Using custom plugins: Open the app project build.gradle, apply the custom Gradle plugin, and Async. “` apply plugin: ‘com.android.application’ apply plugin: ‘com.android.gradle’

android { ... }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}Copy the code
  1. Create extended attributes:

In Android {}, you can configure parameters such as compileSdkVersion. Essentially, you create a javaBean in gradle script closure and pass it to your plug-in for reading.

Steps: 1. Create an entity class and declare member variables that receive the parameters configured in Gradle. Groovy is a javaBean. Groovy is a javaBean. Java) class ReleaseInfoExtension {String versionCode String versionName String versionInfo String fileName ReleaseInfoExtension() {} @Override String toString() { return "versionCode = ${versionCode} , versionName = ${versionName} ," + " versionInfo = ${versionInfo} , fileName = ${fileName}" } } ``` 2. In the custom plug-in, extend the current project. Class GradleStudyPlugin implements Plugin<Project> {@param Project implements the current Plugin's Project */ @override Void apply(Project Project) {// A releaseInfo extension can be initialized using a releaseInfo closure in a Gradle script. project.extensions.create("releaseInfo", ReleaseInfoExtension) } } ``` 3. Open build.gradle in the app project and configure the specified parameters by extending the named closure with the key value. ``` apply plugin: 'com.android.gradle' releaseInfo {versionCode = '1.0.0' versionName = '100' versionInfo = 'first app info' fileName = 'release.xml' } ``` 4. Receive parameters ` ` ` def versionCodeMsg = project. Extensions. ReleaseInfo. VersionCode ` ` `Copy the code
  1. Create extension Task:

A custom plug-in encapsulates some common tasks, so extending tasks is the most important part of a custom plug-in. Extending tasks is also easy by inheriting DefaultTask and writing TaskAction annotation methods. // Example: The app version information written to the XML file import groovy. XML. MarkupBuilder import org. Gradle. API. DefaultTask import org.gradle.api.tasks.TaskAction

Class ReleaseInfoTask extends DefaultTask {ReleaseInfoTask() {group 'android' // Specifies a group description 'Update the release Info '// Add a description} /** * Using TaskAction annotations, you can make methods execute at gradle execution stage. * doFirst is simply adding execution logic externally to the front of @TaskAction. * doLast externally adds execution logic to the end of @TaskAction. */ @taskAction void doAction() {updateInfo()} private void updateInfo() {def versionCodeMsg = project.extensions.releaseInfo.versionCode def versionNameMsg = project.extensions.releaseInfo.versionName def versionInfoMsg = project.extensions.releaseInfo.versionInfo def fileName = project.extensions.releaseInfo.fileName // Def file = project.file(fileName) if (file! = null && ! File.exists ()) {file.createnewfile ()} // Create the class needed to write XML data. def sw = new StringWriter(); Def xmlBuilder = new groovy.xml.markupBuilder (sw) // Create a realEase node if (file.text! = null && file.text.size() <= 0) { xmlBuilder.releases { release { versionCode(versionCodeMsg) versionName(versionNameMsg) versionInfo(versionInfoMsg) } } file.withWriter { writer -> writer.append(sw.toString()) } } Else {// Append to the original content if there is already content in the XML file. xmlBuilder.release { versionCode(versionCodeMsg) versionName(versionNameMsg) versionInfo(versionInfoMsg) } def lines = file.readLines() def lengths = lines.size() - 1 file.withWriter { writer -> lines.eachWithIndex { String line, int index -> if (index ! = lengths) { writer.append(line + '\r\n') } else if (index == lengths) { writer.append(sw.toString() + '\r\n') Writer.append (line + '\r\n')}}}}}} ' 'Like creating extended attributes, extending tasks also requires creating an injection in project. /** * GradleStudyPlugin implements Plugin<Project> {/** ** param Project // Create extension properties // In gradle scripts, A releaseInfo extension is initialized through the releaseInfo closure. Project. Extensions. The create (" releaseInfo, "ReleaseInfoExtension) / / create Task project. The tasks. The create (" updateReleaseInfo", ReleaseInfoTask)}} "" after Async project, you can see the custom Task in the Android group in the Gradle tag of Idea. Note: This plugin is visible only to the current project, so if we want to use our grdle plugin for other projects, we need to create a separate library project, create all the files in the buildSrc directory, and upload it to the Maven repositoryCopy the code
  1. For Demo, see github.com/Endless5F/J…

Use custom plug-ins in standalone Modules

Note To define a custom plug-in in an independent Module, follow the following steps in sequence.

Building custom Gradle plug-ins in buildSrc will only be used in the current project, so for common plug-ins, it is usually a separate Module to create custom Gradle plug-ins.

1. Create Android Library Module

First, in the main project, create a normal Android Library Module and delete its default directory. Change it to the directories needed by the Gradle plugin, that is, all the directories in the buildSrc directory, as shown in the figure below:

As shown above, the files created are exactly the same as those created in the buildSrc directory, except that the plug-in is created in a custom Module instead of the default buildSrc directory.

2. Configure the build.gradle script in the current Module

Build. Gradle creates a plugin using a custom Module, so you can’t let Gradle load the plugin automatically. Instead, you need to manually deploy the plugin.


plugins {
    id 'kotlin'
    id 'maven'
}

repositories {
    mavenCentral()
}

dependencies {
    compileOnly gradleApi()
    compileOnly localGroovy()
    implementation "Org. Ow2. Asm: asm: 9.1"
    implementation "Org. Ow2. Asm: asm - Commons: 9.1"
    implementation "Com. Android. Tools. Build: gradle: 2"
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

uploadArchives {
    repositories.mavenDeployer {
        repository(url: uri('.. /repo')) // The path to the repository, here is the repo folder under the project root directory
        pom.groupId = 'com.debug.plugin'  // groupId, self-defined, usually package name
        pom.artifactId = 'plugin' // artifactId, custom
        pom.version = '1.0.0' // version Indicates the version number}}Copy the code
3. Release plug-ins

Instead of the build.gradle script in buildSrc, Maven support is added and uploadArchives is a Task to deploy this Module to the local repO directory. Execute the./gradlew uploadArchives directive in the terminal to deploy the plug-in to the REPO directory, as shown in the following figure:

When the plug-in is deployed locally, it can be referenced in the main project.

When the plug-in is officially released, it can be published to the central library like any other module, so that it can be used as a library project in the central library.

4. Configure published plug-ins

Configure the plugin just published to the repo directory into the build.gradle script of the rootProject, as shown in the following figure:

5. Reference custom plug-ins

Note To define a custom plug-in in an independent Module, perform the preceding steps one by one.

Android plugin for Gradle extension

  1. The translator sequence | Gradle Android plugin user guide translation
  2. Manipulation tasks (task) | Gradle Android plugin user guide translation
  3. Custom Apk output position:
    this.afterEvaluate { this.android.applicationVariants.all { variant -> def output = variant.outpus.first() // Outputs returns a set, but only one element, Def apkName = "app-${variant. BaseName}-${variant. VersionName}.apk" outputFile = new File(output.outputFile.parent, apkName) } }Copy the code

Jenkins

Jenkins is an open source continuous integration (CI) tool that provides a user-friendly interface. Originated in Hudson (Hudson is commercial), Jenkins is mainly used for continuous, automated building/testing of software projects and monitoring the execution of external tasks. Jenkins is written in the Java language and can run in popular servlet containers such as Tomcat or on its own. It is often used in combination with version management tools (SCM) and build tools. Common version control tools include SVN and GIT, and build tools include Maven, Ant, and Gradle.

For details, please refer to Jenkins’ detailed tutorial

Refer to the link

www.bilibili.com/video/av415…

www.jianshu.com/p/498ae3fab…

www.jianshu.com/u/f9de25923…

.

Note: if there is anything wrong, please correct it. Looking forward to your thumbs up!!