Gradle系列相关文章 1、Gradle理论与实践一:Gradle入门
2、Gradle理论与实践二:Groovy介绍
3、Gradle理论与实践三:Gradle构建脚本根底
4、Gradle理论与实践四:自界说Gradle插件
5、Gradle装备subprojects和allprojects的区别:subprojects和allprojects的区别

Gradle插件

Gradle能够认为是一个结构,负责界说流程和规则。而具体的编译作业则是经过插件的方法来完成的。比方编译 JavaJava 插件,编译 GroovyGroovy 插件,编译 Android APPAndroid APP 插件,编译 Android LibraryAndroid Library 插件。在Gradle中一般有两种类型的插件,脚本插件二进制插件。运用插件方法能够使得同一逻辑在项目中复用,也能够针对不同项目做个性化装备,只需插件代码支撑即可。

一、Java Gradle插件

Java插件引入方法:

apply plugin: 'java'

Java插件约好src/main/java为咱们项目源代码寄存方位;src/main/resources为资源寄存方位;src/test/java为咱们单元测试用例寄存目录;src/test/resources寄存咱们单元测试中资源寄存方位。 java插件引入了一个概念叫做SourceSets,经过修改SourceSets中的特点,能够指定哪些源文件(或文件夹下的源文件)要被编译,哪些源文件要被排除。Gradle就是经过它完成Java项目的布局界说。

默认装备:

android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
}

假如想修改源代码的目录以及多个resource的目录,能够经过下面来设置:

  sourceSets {
        main {
            java.srcDirs = ['other/java']
            res.srcDirs =
                    [                            'src/main/res/',                            'src/main/res/extra'                    ]
        }
    }

更多设置请移步官网: https://developer.android.com/studio/build/build-variants

二、Android Gradle插件

Android其实就是Gradle的一个第三方插件,Android GradleAndroid Studio完美无缝搭配的新一代构建体系。

  • APP插件id :com.android.application
  • Library插件id:com.android.library
  • Test插件id:com.android.test

2.1、运用Android Gradle插件

上面说了Android GradleGradle的一个三方插件,托管在jcenter上,假如要运用,有必要知道他们的插件id,另外还要装备他们依靠的classpath,在根目录的build.gradle中装备如下:

buildscript {
    repositories {
        //代码库房
        jcenter()
    }
    dependencies {
        //Android Gradle插件版别
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
}

装备代码库房为jcenter(注:文章编写时间较早,现在jcenter现已不再更新了,新项目中请改为google()mavenCentral()),当编译项目时,Gradle会去jcenter库房中寻找Android Gradle对应版别的依靠,以上装备好后,就能够运用Android Gradle插件了,在咱们app目录的build.gradle下:

apply plugin: 'com.android.application
android {
    compileSdkVersion 26 
    buildToolsVersion "26.0.3"
    defaultConfig {
        applicationId "org.ninetripods.qrcode"
        minSdkVersion 14
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        release {
            keyAlias 'xxx'
            keyPassword 'xxx'
            storeFile file('xxx.jks')
            storePassword 'xxx'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

android{}Android Gradle插件提供的一个扩展类型,能够让咱们自界说Android Gradle工程。

  • compileSdkVersion: compileSdkVersion告知Gradle用哪个Android SDK版别编译运用。 1、运用想兼容新版别、运用了新版别API,此时就有必要运用新版别及以上版别编译,不然就会编译报错; 2、假如运用了新版别的Support Library,此时也有必要运用新版别及以上版别编译
  • buildToolsVersion:构建该Android工程所用构建工具(aapt, dx, renderscript compiler, etc...)的版别,一般google在发布新的SDK时,会一起发布对应的buildToolsVersion,更具体的见:https://stackoverflow.com/questions/24521017/android-gradle-buildtoolsversion-vs-compilesdkversion PS:Android Studio 3.0以上时,buildToolsVersion不是有必要要写的了。
  • defaultConfig: 默认装备,它是一个ProductFlavorProductFlavor允许咱们在打多渠道包时根据不同的情况生成不同的APK包。即假如不在ProductFlavor中独自装备的话,那么会运用defaultConfig的默认装备。
  • minSdkVersion: 最低支撑的Android体系API Level
  • targetSdkVersion: App基于哪个Android版别开发的
  • versionCode: App运用内部版别号,一般用来控制App晋级
  • versionName: App运用的版别名称,即咱们发布的App版别,一般用户能够看到。

minSdkVersion、targetSdkVersion、compileSdkVersion三者的联系: minSdkVersion <= targetSdkVersion <= compileSdkVersion

理想状况是: minSdkVersion(lowest possible) <= targetSdkVersion == compileSdkVersion(latest SDK)

三、自界说Gradle插件

编写自界说Gradle插件源代码的有下面三个地方:

3.1、Build script

能够在构建脚本中直接编写自界说插件的源代码。这样做的好处是插件能够主动编译并包含在构建脚本的classpath中,不需要再去声明。然而,这个自界说插件在构建脚本之外是不行见的,因此这种方法完成的插件在构建脚本之外是不能复用。举个比如,在根目录下的build.gradle中写入:

   //build.gradle
   class GreetingPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        //新建task hello
        project.task('hello') {
            doLast {
                println 'Hello from the GreetingPlugin'
            }
        }
    }
}
//引入插件
apply plugin: GreetingPlugin

履行成果

./gradlew hello
Hello from the GreetingPlugin

3.2、buildSrc project

在项目的根目录下新建一个buildSrc/src/main/groovy的目录,将自界说插件的源代码放入此目录中,Gradle将负责编译和测试插件,并使其在构建脚本的classpath中可见。这个插件对于项目中一切的build script都是可见的,但是在构建之外是不行见的,此构建方法不能再其他项目中复用。 举例:在rootProjectDir/buildSrc/src/main/groovy目录下新建了一个插件类,如下:

Gradle理论与实践四:自定义Gradle插件

GreetingExtensionPlugin.groovy中代码如下:

//GreetingExtensionPlugin.groovy
package com
import org.gradle.api.Plugin
import org.gradle.api.Project
class GreetingExtensionPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // Add the 'greeting' extension object
        def extension = project.extensions.create('greeting', GreetingExtension)
        // Add a task that uses configuration from the extension object
        project.tasks.create('buildSrc') {
            doLast {
                println "${extension.message} from ${extension.greeter}"
                println project.greeting
            }
        }
    }
}
class GreetingExtension {
    String message
    String greeter
}

界说好的插件就能够在项目中一切的build.gradle中运用了:

//build.gradle
apply plugin: GreetingExtensionPlugin
greeting {
    message = 'hello'
    greeter = 'GreetingExtensionPlugin'
}

履行成果:

./gradlew buildSrc
hello from GreetingExtensionPlugin
com.GreetingExtension_Decorated@42870556
  • 扩展特点:自界说插件代码中有一句def extension = project.extensions.create('greeting', GreetingExtension),能够用来扩展特点,能够理解为往GreetingExtension中新加了一个特点。创立完成后,能够经过project.greeting来获取扩展特点的实例。运用这种方法来给插件传递参数。

3.3、Standalone project

上面两种自界说插件都只能在自己的项目中运用,假如想在其他项目中也能复用,能够创立一个独自的项目并把这个项目发布成一个JAR,这样多个项目中就能够引入并同享这个JAR。一般这个JAR包含一些插件,或者将几个相关的task捆绑到一个库中,或者是插件和task的组合, Standalone project创立过程:

  • Android StudiorootProject目录下新建一个Module,类型随意选一个就行(如 Android Module),后边会有大的改动。(也能够选择IDEA来开发,IDEA中能够直接创立groovy组件)
  • 清空Module目录下build.gradle中的一切内容,删除其他一切文件
  • 在Module中创立src/main/groovy的目录,然后再创立包名文件夹。在main目录下再新建resources/META-INF/gradle-plugins目录,在这个目录下编写一个和插件id姓名相同的.properties文件,这样Gradle就能够找到插件完成了。

举个比如,下面的代码完成了在build目录中新建个文本文件,并写入文本的功用。 1、在src/main/groovy下新建/com/fastgo/plugin目录并创立一个名为CustomPlugin.groovy的文件:

package com.fastgo.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.tasks.TaskAction
class CustomPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.tasks.create('writeToFile', CustomPluginTask) {
            destination = { project.greetingFile }
            doLast {
                println project.file(destination).text
            }
        }
    }
}
class CustomPluginTask extends DefaultTask {
    def destination
    File getDestination() {
        //创立路径为destination的file
        project.file(destination)
    }
    @TaskAction
    def greet() {
        def file = getDestination()
        file.parentFile.mkdirs()
        //向文件中写入文本
        file.write('hello world')
    }
}

上面的代码中在插件的apply(Project project)中创立了名为writeToFile的Task,并依靠于CustomPluginTaskCustomPluginTask中界说了一个destination路径,并经过project.file(destination)创立创立一个路径为destination的文件,并往文件中写入文本。

注意:别忘了引入 package com.fastgo.plugin,不然终究生成后会提示找不到插件。

2、创立resources/META-INF/gradle-plugins/com.fastgo.plugin.properties文件,并在文件里写入:

implementation-class=com.fastgo.plugin.CustomPlugin

3、在build.gradle中写入:

plugins {
    id 'groovy'
    id 'maven-publish'
    id 'maven'
}
dependencies {
    implementation gradleApi()
    implementation localGroovy()
}
repositories {
    mavenCentral()
}
group = 'com.fastgo'
version = '1.0-test'
publishing {
    repositories {
        maven {
            url = uri("$rootDir/repo")
        }
    }
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
}

本例中是经过url = uri("$rootDir/repo")将代码打包到maven的本地库房中,假如想上传到远端,换成远端链接即可。经过设置GroupId、ArtifactId、Version来确保插件的唯一性。

  • GroupId: group = 'com.fastgo'
  • ArtifactId: plugin
  • Version: version = '1.0-test'

终究的文件如下:

Gradle理论与实践四:自定义Gradle插件

插件编写完成后,在Android Studio的右上角翻开Gradle,履行:plugin分组中的publish指令,履行完成后,会在项目根目录下生成repo库房:

Gradle理论与实践四:自定义Gradle插件
4、在项目根目录的build.gradle中引证插件:

buildscript {
    repositories {
        maven {
            url = uri("$rootDir/repo")
        }
       ------其他-------
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.fastgo:plugin:1.0-test'
    }
}
 //经过插件id找到插件
 apply plugin: 'com.fastgo.plugin'
 ext.greetingFile="$buildDir/hello.txt"

5、验证作用

mqdeMacBook-Pro:AndroidStudy mq$ ./gradlew -q writeToFile
hello world

履行writeToFiletask输出了咱们写入的文本,再看看build目录下是否有咱们想要的文件:

Gradle理论与实践四:自定义Gradle插件

能够看到在build目录下生成了hello.txt文件并往里面写入了设置的文本,说明咱们编写的插件被成功引入了。

四、源码地址

上述比如源码已上传至:https://github.com/crazyqiang/AndroidStudy

五、材料

【1】https://docs.gradle.org/current/userguide/custom_plugins.html 【2】https://docs.gradle.org/4.1/userguide/publishing_maven.html 【3】https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html