Gradle理论与奉行,开荒贰个自身的

使用 Kotlin , Groovy ,Java 开发一个自己的 Gradle 插件

Gradle可以认为是一个框架,负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译
Java 有 Java 插件,编译 Groovy 有 Groovy 插件,编译 Android APP 有
Android APP 插件,编译 Android Library 有 Android Library
插件。在Gradle中一般有两种类型的插件,脚本插件必发365游戏官方网址,二进制插件。使用插件方式可以使得同一逻辑在项目中复用,也可以针对不同项目做个性化配置,只要插件代码支持即可。

Gradle系列相关文章:1、Gradle理论与实践一:Gradle入门2、Gradle理论与实践二:Groovy介绍3、Gradle理论与实践三:Gradle构建脚本基础4、Gradle理论与实践四:自定义Gradle插件5、Gradle配置subprojects和allprojects的区别:subprojects和allprojects的区别

先上效果图:

Java插件引入方式:

Gradle可以认为是一个框架,负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译
Java 有 Java 插件,编译 Groovy 有 Groovy 插件,编译 Android APP 有
Android APP 插件,编译 Android Library 有 Android Library
插件。在Gradle中一般有两种类型的插件,脚本插件二进制插件。使用插件方式可以使得同一逻辑在项目中复用,也可以针对不同项目做个性化配置,只要插件代码支持即可。

必发365游戏官方网址 1必发365游戏官方网址 2image.png

  • apply plugin: ‘java’

Java插件引入方式:

功能说明:

Java插件约定src/main/java为我们项目源代码存放位置;src/main/resources为资源存放位置;src/test/java为我们单元测试用例存放目录;src/test/resources存放我们单元测试中资源存放位置。java插件引入了一个概念叫做SourceSets,通过修改SourceSets中的属性,可以指定哪些源文件(或文件夹下的源文件)要被编译,哪些源文件要被排除。Gradle就是通过它实现Java项目的布局定义。

  • apply plugin: ‘java’

korGenerate:

自动生成 Entity,Dao,Controller 模板代码

默认配置:

Java插件约定src/main/java为我们项目源代码存放位置;src/main/resources为资源存放位置;src/test/java为我们单元测试用例存放目录;src/test/resources存放我们单元测试中资源存放位置。java插件引入了一个概念叫做SourceSets,通过修改SourceSets中的属性,可以指定哪些源文件(或文件夹下的源文件)要被编译,哪些源文件要被排除。Gradle就是通过它实现Java项目的布局定义。

korFront:

自动 copy 前端 front 工程目录下面的 —— nowa 构建的 dist
目录下的静态资源文件:html, css, js

必发365游戏官方网址 3image.png必发365游戏官方网址 4image.png必发365游戏官方网址 5image.png必发365游戏官方网址 6image.png必发365游戏官方网址 7image.png

build.gradle

group 'com.easykotlin.plugin'version '1.0-SNAPSHOT'buildscript { ext.kotlin_version = '1.2.0' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" }}apply plugin: 'groovy'apply plugin: 'java'apply plugin: 'kotlin'apply plugin: 'maven'sourceCompatibility = 1.8repositories { mavenCentral()}dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compile 'org.codehaus.groovy:groovy-all:2.3.11' testCompile group: 'junit', name: 'junit', version: '4.12' compile gradleApi()}compileKotlin { kotlinOptions.jvmTarget = "1.8"}compileTestKotlin { kotlinOptions.jvmTarget = "1.8"}

必发365游戏官方网址 8image.png

其中,compile gradleApi() 是使用 Gradle 的 API 依赖。

配置上传到 maven 仓库,这里我们配置上传至本机的目录下:

apply plugin: 'maven'uploadArchives { repositories { mavenDeployer { repository(url: uri('/Users/jack/.m2/repository')) } }}

点击右侧工具栏的: upload > uploadArchives

必发365游戏官方网址 9image.png

执行日志:

23:41:48: Executing external task 'uploadArchives'...:compileKotlin UP-TO-DATE:compileJava NO-SOURCE:processResources UP-TO-DATE:classes UP-TO-DATE:jar UP-TO-DATE:uploadArchivesBUILD SUCCESSFUL in 0s4 actionable tasks: 1 executed, 3 up-to-date23:41:49: External task execution finished 'uploadArchives'.

看一下本机的上传情况:

~/.m2/repository/com/easykotlin/plugin/kor$ tree .├── 1.0-SNAPSHOT│ ├── kor-1.0-20171221.172201-1.jar│ ├── kor-1.0-20171221.172201-1.jar.md5│ ├── kor-1.0-20171221.172201-1.jar.sha1│ ├── kor-1.0-20171221.172201-1.pom│ ├── kor-1.0-20171221.172201-1.pom.md5│ ├── kor-1.0-20171221.172201-1.pom.sha1│ ├── kor-1.0-20171221.172210-2.jar│ ├── kor-1.0-20171221.172210-2.jar.md5│ ├── kor-1.0-20171221.172210-2.jar.sha1│ ├── kor-1.0-20171221.172210-2.pom│ ├── kor-1.0-20171221.172210-2.pom.md5│ ├── kor-1.0-20171221.172210-2.pom.sha1│ ├── maven-metadata-remote.xml│ ├── maven-metadata-remote.xml.sha1│ ├── maven-metadata.xml│ ├── maven-metadata.xml.md5│ ├── maven-metadata.xml.sha1│ └── resolver-status.properties├── maven-metadata-remote.xml├── maven-metadata-remote.xml.sha1├── maven-metadata.xml├── maven-metadata.xml.md5├── maven-metadata.xml.sha1└── resolver-status.properties1 directory, 24 files

其中,kor-1.0-20171221.154128-1.pom 文件的内容是:

<?xml version="1.0" encoding="UTF-8"?><project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.easykotlin.plugin</groupId> <artifactId>kor</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> <version>1.2.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies></project>

新建Gradle 插件的执行逻辑的实现类

必发365游戏官方网址 10image.png必发365游戏官方网址 11image.png必发365游戏官方网址 12image.png

实现代码编写:

必发365游戏官方网址 13image.png必发365游戏官方网址 14image.png

package com.easykotlin.korimport org.gradle.api.Pluginimport org.gradle.api.Projectclass KorPlugin implements Plugin<Project>{ @Override void apply(Project project) { }}

具体实现代码:

package com.easykotlin.korimport org.gradle.api.Pluginimport org.gradle.api.Projectclass KorPlugin implements Plugin<Project> { @Override void apply(Project project) { project.task << { println("Hello, Kor !") println(project.group.toString println(project.artifacts.toString } project.task("nowabuild") << { NowaBuildJava nb = new NowaBuildJava() String projectDir = project.projectDir.absolutePath println("projectDir = $projectDir") nb.nowaBuild(projectDir) } }}

kor.properties

implementation-class=com.easykotlin.kor.KorPlugin

必发365游戏官方网址 15image.png

build.gradle

group 'com.easykotlin.plugin'version '1.0-SNAPSHOT'buildscript { ext.kotlin_version = '1.2.0' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" }}apply plugin: 'groovy'apply plugin: 'java'apply plugin: 'kotlin'apply plugin: 'maven'sourceCompatibility = 1.8repositories { mavenCentral()}dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"// compile 'org.codehaus.groovy:groovy-all:2.4.11' testCompile group: 'junit', name: 'junit', version: '4.12' compile gradleApi()}compileKotlin { kotlinOptions.jvmTarget = "1.8"}compileTestKotlin { kotlinOptions.jvmTarget = "1.8"}uploadArchives { repositories { mavenDeployer { repository(url: uri('/Users/jack/.m2/repository')) } }}

必发365游戏官方网址 16image.png

然后,我们在另外项目 reakt 中使用刚才开发的插件:

build.gradle

buildscript { ext { kotlinVersion = '1.2.0' springBootVersion = '2.0.0.M7' } repositories { mavenLocal() mavenCentral() maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") classpath('com.easykotlin.plugin:kor:1.0-SNAPSHOT') }}apply plugin: 'com.easykotlin.kor'......

必发365游戏官方网址 17image.png必发365游戏官方网址 18image.png

Gradle 插件工程源代码:

使用插件的工程源代码:

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的目录,可以通过下面来设置:

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'] }}
 sourceSets { main { java.srcDirs = ['other/java'] res.srcDirs = [ 'src/main/res/', 'src/main/res/extra' ] } }

如果想修改源代码的目录以及多个resource的目录,可以通过下面来设置:

更多设置请移步官网:

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

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

更多设置请移步官网:

  • APP插件id :com.android.application

  • Library插件id:com.android.library

  • Test插件id:com.android.test

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

2.1、应用Android Gradle插件

上面说了Android
Gradle是Gradle的一个三方插件,托管在jcenter上,如果要使用,必须知道他们的插件id,另外还要配置他们依赖的classpath,在根目录的build.gradle中配置如下:

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

配置代码仓库为jcenter,当编译项目时,Gradle会去jcenter仓库中寻找Android
Gradle对应版本的依赖,以上配置好后,就可以使用Android
Gradle插件了,在我们app目录的build.gradle下:

apply plugin: 'com.android.applicationandroid { 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,更详细的见:
    Studio 3.0以上时,buildToolsVersion不是必须要写的了。

  • defaultConfig:
    默认配置,它是一个ProductFlavor。ProductFlavor允许我们在打多渠道包时根据不同的情况生成不同的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插件源代码的有下面三个地方:

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

3.1、Build script

可以在构建脚本中直接编写自定义插件的源代码。这样做的好处是插件可以自动编译并包含在构建脚本的classpath中,不需要再去声明。然而,这个自定义插件在构建脚本之外是不可见的,因此这种方式实现的插件在构建脚本之外是不能复用。举个例子,在根目录下的build.gradle中写入:

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

执行结果

 ./gradlew helloHello from the GreetingPlugin

2.1、应用Android Gradle插件

上面说了Android
Gradle是Gradle的一个三方插件,托管在jcenter上,如果要使用,必须知道他们的插件id,另外还要配置他们依赖的classpath,在根目录的build.gradle中配置如下:

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

配置代码仓库为jcenter,当编译项目时,Gradle会去jcenter仓库中寻找Android
Gradle对应版本的依赖,以上配置好后,就可以使用Android
Gradle插件了,在我们app目录的build.gradle下:

apply plugin: 'com.android.applicationandroid { 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,更详细的见:
    Studio 3.0以上时,buildToolsVersion不是必须要写的了。

  • defaultConfig:
    默认配置,它是一个ProductFlavor。ProductFlavor允许我们在打多渠道包时根据不同的情况生成不同的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插件源代码的有下面三个地方:

3.2、buildSrc project

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

必发365游戏官方网址 19image.png

GreetingExtensionPlugin.groovy中代码如下:

//GreetingExtensionPlugin.groovypackage comimport org.gradle.api.Pluginimport org.gradle.api.Projectclass 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.gradleapply plugin: GreetingExtensionPlugingreeting { message = 'hello' greeter = 'GreetingExtensionPlugin'}

执行结果:

./gradlew buildSrchello from GreetingExtensionPlugincom.GreetingExtension_Decorated@42870556
  • 扩展属性:自定义插件代码中有一句def extension = project.extensions.create('greeting', GreetingExtension),可以用来扩展属性,可以理解为往GreetingExtension中新加了一个属性。创建完成后,可以通过project.greeting来获取扩展属性的实例。使用这种方式来给插件传递参数。

3.1、Build script

可以在构建脚本中直接编写自定义插件的源代码。这样做的好处是插件可以自动编译并包含在构建脚本的classpath中,不需要再去声明。然而,这个自定义插件在构建脚本之外是不可见的,因此这种方式实现的插件在构建脚本之外是不能复用。举个例子,在根目录下的build.gradle中写入:

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

执行结果

./gradlew helloHello from the GreetingPlugin

3.3、Standalone project

上面两种自定义插件都只能在自己的项目中使用,如果想在其他项目中也能复用,可以创建一个单独的项目并把这个项目发布成一个JAR,这样多个项目中就可以引入并共享这个JAR。通常这个JAR包含一些插件,或者将几个相关的task捆绑到一个库中,或者是插件和task的组合,
Standalone project创建步骤:

  • 在Android
    Studio的rootProject目录下新建一个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.pluginimport org.gradle.api.DefaultTaskimport org.gradle.api.Projectimport org.gradle.api.Pluginimport org.gradle.api.tasks.TaskActionclass 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'

最终的文件如下:

必发365游戏官方网址 20image.png

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

必发365游戏官方网址 21image.png

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 writeToFilehello world

执行writeToFile的task输出了我们写入的文本,再看看build目录下是否有我们想要的文件:

必发365游戏官方网址 22image.png

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

上述例子源码已上传至:

必发365游戏官方网址 23image必发365游戏官方网址 24image

3.2、buildSrc project

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

必发365游戏官方网址 19image.png

GreetingExtensionPlugin.groovy中代码如下:

//GreetingExtensionPlugin.groovypackage comimport org.gradle.api.Pluginimport org.gradle.api.Projectclass 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.gradleapply plugin: GreetingExtensionPlugingreeting { message = 'hello' greeter = 'GreetingExtensionPlugin'}

执行结果:

./gradlew buildSrchello from GreetingExtensionPlugincom.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
    Studio的rootProject目录下新建一个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.pluginimport org.gradle.api.DefaultTaskimport org.gradle.api.Projectimport org.gradle.api.Pluginimport org.gradle.api.tasks.TaskActionclass 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'

最终的文件如下:

必发365游戏官方网址 20image.png

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

必发365游戏官方网址 21image.png4、在项目根目录的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 writeToFilehello world

执行writeToFile的task输出了我们写入的文本,再看看build目录下是否有我们想要的文件:

必发365游戏官方网址 22image.png

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

上述例子源码已上传至:

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website