Gradle插件让我们把可以复用的构建逻辑打包起来,这样就可以用到其他项目当中。我们可以在Gradle中引用自己的自定义插件。下面介绍几种自定义插件的方法:
- Build script
- buildSrc project
- Standalone project
Build script
这种方式直接把插件的代码写入build script当中,好处是除了编写代码之外不用配置其他的引入参数,坏处就是只能在此build script当中使用这个插件,无法复用。在创建自定义插件时需要编写一个插件的实现。 Gradle实例化插件并使用Plugin.apply()方法调用插件实例。当我们引用插件时:“apply plugin: 'id'”,apply()方法就会被执行。
新建一个自定义插件
apply plugin: 'com.android.application'
apply plugin: MyCustomGradle
class MyCustomGradle implements Plugin<Project>{
@Override
void apply(Project project) {
project.task("customplugin"){
doLast {
println "This is my custom plugin!"
}
}
}
}
android {
......
}
运行这个插件定义的Task:
D:\Android\Workspace\CustomGradlePlugin>gradlew "customplugin"
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory. It is currently set to D:\Android\sdk\ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.
Incremental java compilation is an incubating feature.
:app:customplugin
This is my custom plugin!
BUILD SUCCESSFUL
Total time: 2.29 secs
值得注意的是Gradle会为每个引用这个插件的project创建一个这个plugin 的实例。在apply中给Project添加了一个新属性,然后在script中配置这个属性的值。配置的时候这个配置块的名字要和新属性的名字对应。这里要注意apply的时候并没有执行到script,所以如果在apply中获取配置的值是获取不到的,需要在task里面添加doLast或doFirst,等到执行task的时候再去获取值。
从脚本中获取输入
大多数的插件都需要从build script当中获取配置信息。Project通过ExtensionContainer来追踪那些传给插件的配置信息。为了能够从脚本中获取信息,我们要在extension container中添加一个Java Bean:
project.extensions.create("myplugin", MyPluginExtension)
MyPluginExtension:
class MyPluginExtension{
String message;
}
这样我们就在Project中新建了一个名为“myPlugin”且类型为“MyPluginExtension”的属性,可以直接通过project.myPlugin访问。而且在分析到myPlugin{}这个script block时就会把{}这个闭包的代理设置为MyPluginExtension,在MyPluginExtension的上下文中运行这个闭包。
myplugin{
message "Thank you!";
}
就相当于:
myPluginExtension.setMessage("Thank you!")
因为Groovy会自动加上setter和getter,所以我们在定义MyPluginExtension时不必再写。之后再插件中获取配置的值的方式则为:
project.myPlugin.message
整个代码片段:
apply plugin: 'com.android.application'
apply plugin: MyCustomGradle
class MyCustomGradle implements Plugin<Project>{
@Override
void apply(Project project) {
project.extensions.create("myplugin", MyPluginExtension)
project.task("customplugin"){
doLast {
println "This is my custom plugin!" + project.myplugin.message;
}
}
}
}
class MyPluginExtension{
String message;
}
myplugin{
message "Thank you!";
}
执行Task:
D:\Android\Workspace\CustomGradlePlugin>gradlew "customplugin"
NDK is missing a "platforms" directory.ompiling
......
:app:customplugin
This is my custom plugin!Thank you!
BUILD SUCCESSFUL
Total time: 2.802 secs
buildSrc project
单独写Gradle Plugin文件,放在rootProjectDir/buildSrc/src/main/groovy/目录下,同一个工程中所有的构建文件都可以引用这个插件,但是不能被其他工程引用。
新建一个名为buildSrc的工程,再构建如下目录,这里的buildSrc是多工程项目:
buildSrc/build.gradle:
buildscript {
repositories {
mavenCentral()
}
}
my-gradle-plugin/build.gradle:
apply plugin:'groovy'
repositories {
mavenCentral()
}
rootProject.dependencies{
runtime project(path)
}
dependencies {
compile localGroovy()
compile gradleApi()
}
因为这里buildSrc底下有多个工程,所以要配置rootProject.dependencies{},同时还要设置仓库,不然编译的时候会找不到插件。官方文档的说法是:
The buildSrc project can be a multi-project build, just like any other regular multi-project build. However, all of the projects that should be on the classpath of the actual build must be runtime dependencies of the root project in buildSrc.
要在每个插件子工程的build.gradle中都配置runtime依赖。
接着settings.gadle,如果是多项目这个文件一定不能忘记:
include "plugins/my-gradle-plugin"
myplugin.properties:
implementation-class=com.example.plugin.AppPlugin
这个文件的目的主要是设置插件的id,告诉Gradle这个插件的入口类在哪里。像上面那样配置之后我们就可以这样引入这个插件:
apply plugin: 'myplugin'
如果没有通过properties文件指定id,这样引入插件也行:
apply plugin: com.example.plugin.AppPlugin.class
之后在同工程的app中引用这个插件:
apply plugin: 'com.android.application'
apply plugin: 'myplugin'
myplugin{
message "buildSrc!"
}
运行Task:
D:\Android\Workspace\MyBuildSrc>gradlew -q customplugin
This is my custom plugin!buildSrc!
采用buildSrc project这种方式来整合插件虽然看起来简单,不需要再配置classpath直接就能在其他子工程中引用,但是具体实现起来很麻烦,编译的时候常常提示找不到自定义的插件。有时候可能是因为在buildSrc在编译并添加到classpath之前子项目的build script就已经被编译且缓存了,这时候可以利用“gradlew --recompile-scripts”来强制重新编译。
Standalone project
这种方法把我们的插件代码移到一个独立的项目当中,这样我们就可以发布或者和别人分享我们的插件。这个项目简单来说就是构建一个JAR包,这个JAR包包含了我们在插件中所写的类。
构建JAR包
首先新建一个Android Library的module,名为“myplugin“。把myplugin的build.gradle文件的内容改为:
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies{
compile gradleApi()//gradle sdk
compile localGroovy()//groovy sdk
compile fileTree(dir: 'libs', include: ['*.jar'])
}
uploadArchives {
repositories{
mavenDeployer {
repository(url: uri(LOCAL_REPO_URL))
pom.groupId = PROJ_GROUP
pom.artifactId = PROJ_ARTIFACTID
pom.version = PROJ_VERSION
}
}
}
uploadArchives就是打包成Task的配置。其中的配置常量可以写在gradle.properties文件中。设置了pom.groupId、pom.artifactId和pom.version之后,如果我们要引入这个插件,只要在buildscript{}的dependencies{}当中这样设置classpath即可:
classpath 'pom.groupId : pom.artificatId : pom.version'
在myplugin的根目录下新建文件gradle.properties:
PROJ_NAME=myplugin
PROJ_POM_NAME=Local Repository
LOCAL_REPO_URL=D:/repos
PROJ_GROUP=com.example.myplugin
PROJ_ARTIFACTID=myplugin
PROJ_VERSION=1.0.0
PROJ_VERSION_CODE=1
//项目描述
PROJ_WEBSITEURL=http://kvh.io
PROJ_ISSUETRACKERURL=https://github.com/kevinho/Embrace-Android-Studio-Demo/issues
PROJ_VCSURL=https://github.com/kevinho/Embrace-Android-Studio-Demo.git
PROJ_DESCRIPTION=demo apps for embracing android studio
PROJ_LICENCE_NAME=The Apache Software License, Version 2.0
PROJ_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
PROJ_LICENCE_DEST=repo
DEVELOPER_ID=your-dev-id
DEVELOPER_NAME=your-dev-name
DEVELOPER_EMAIL=your-email@your-mailbox.com
这个文件主要配置一些常量。
在main文件夹下面新建一个groovy文件夹和一个resources文件夹:
在groovy文件夹下面新建com.example.myplugin的包,在包下面分别新建MyCustomGradle.groovy文件和MyPluginExtension.groovy文件。接着在resources文件夹下面新建名为META-INF的文件夹,再在META-INF下面新建gradle-plugins文件夹,在gradle-plugins文件夹下面新建com.example.myplugin.properties文件。在这个文件中写好入口类:
//入口
implementation-class = com.example.myplugin.MyCustomGradle
这里com.example.myplugin.properties的命名需要注意,比如我命名为com.example.myplugin.properties,那我后面要在app中引入这个插件时就是这么写的:
apply plugin: com.example.myplugin
这样我的目录结构就成了这样:
Android Studio中会把文件的后缀名隐藏起来,会导致编译出错或找不到自定义的插件,所以要手动补上去。尤其是properties文件和groovy文件。
打开Android Studio右侧的Gradle,找到构建JAR包的Task,运行一下,就生成了我们想要的JAR包:
打开我们指定的生成路径:
在1.0.0文件夹中可以看到一个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.example.myplugin</groupId>
<artifactId>myplugin</artifactId>
<version>1.0.0</version>
</project>
在项目中使用自定义插件
首先要在根项目的build.gradle文件中设置好仓库和依赖:
buildscript {
repositories {
maven{
url uri(LOCAL_REPO_URL)
}
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.example.myplugin:myplugin:1.0.0'
}
}
然后在app module的build.gadle文件中引入插件,并配置好信息:
apply plugin: 'com.android.application'
apply plugin: 'com.example.myplugin'
myplugin{
message "Standlone Project!";
}
......
然后执行这个Task:
D:\Android\Workspace\CustomGradlePlugin>gradlew -p app customplugin
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory. It is currently set to D:\Android\sdk\ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.
Incremental java compilation is an incubating feature.
:app:customplugin
This is my custom plugin!Standlone Project!
BUILD SUCCESSFUL
Total time: 2.758 secs
网友评论