android Gradle插件分类与使用
- 简介
- 作用与优点
- 作用
- 优点
- 插件分类
- 脚本插件
- 对象插件
- 内部插件
- 第三方插件
- 对象插件自定义
- 插件DSL
- Android Gradle 插件
- 分类
- 编写与集成
- 编写
- build.gradle中编写
- buildSrc编写
- 独立项目编写
- 集成
- 插件的生成
- 本地的集成
- 小结
简介
Gradle 是一款非常优秀的构建系统工具,它的DSL基于Groovy实现,可以通过DSL来达到你构建的目的。其中提供了插件的概念,基于Gradle进行很好的扩展,而不改变其核心基础,又能满足不同业务的需要。
这里只说android gradle 插件
从Gradle的角度来说,Android其实就是Gradle的一个第三方插件,由Google开发的。但从Android角度来看,Android插件是基于Gradle构建的,然后加上Gradle Wapper(包装器,保证对于studio运行时,gradle的环境和版本带来一个确定性,并且能快速启动gradle)和studio完美搭建了android构建系统。
作用与优点
作用
- 为项目配置依赖
- 为项目配置约定,比如约定代码的存放位置、签名位置
- 为项目添加任务,比如测试、编译、打包等
- 为项目的核心对象和其他插件的对象添加扩展类型
- 为项目提供公共化配置
优点
- 更高程度的模块化
- 重用和减少维护在多个项目类似的逻辑开销
- 封装必要的逻辑,并允许构建脚本尽可能是声明性的
插件分类
脚本插件
先看代码,根目录定义config.gradle文件:
ext {
cfgs = [
compileSdkVersion : 29
]
android = [
versionName : '1.0.0'
]
}
在根gradle文件中引入插件
apply from: "config.gradle"
task test{
doLast{
println("版本名称是:${android.versionName}")
}
}
执行 ./gradlew test
,会输出:版本名称是:1.0.0
实际上这不算真正的脚本插件,但定义还是脚本插件。更像是c++的头文件引入。
应用脚本插件,其实就是把这个脚本加载进来,使用apply from关键字引入的。但是作用也很大,我们在多模块开发的时候,我们可以庞大的脚本文件,进行分块、分段整理,拆分成一个个公用、职责分明的文件。比如:将很多共有的库版本号一起管理、应用构建版本一起管理、maven配置脚本文件抽取等等。
对象插件
对象插件(二进制插件)是实现了org.gradle.api.Plugin接口的插件。可以分为内部插件和第三方插件。
内部插件
内部插件是gradle提供的,它们可以有plugin id。
比如我们定义一个Java插件
apply plugin : org.gradle.api.plugins.JavaPlugin
由于Gradle会帮我们默认导入org.gradle.api.plugins
包,所以可以省略前缀,如下:
apply plugin :JavaPlugin
更简洁的,对于Gradle自带的核心插件都有一个容易记的短名,称其为plugin id,比如这里的Java插件对应的id就是java,所以简化如下:
apply plugin :'java'
第三方插件
第三方的对象插件通常是jar文件,要想让构建脚本知道第三方插件的存在,需要使用buildscrip来设置依赖,需要配置classpath。
我们最熟悉的android Gradle插件也属于第三方插件,我们经常会这么写:
buildscript {
ext.kotlin_version = '1.3.10'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
然后我们才能引入apply plugin: 'com.android.application'
对象插件自定义
写一个简单的自定义插件,按照标准要实现Plugin
接口:
class GreetingPlugin implements Plugin<Project>{
/**
* Apply this plugin to the given target object.
*
* @param target The target object
*/
@Override
void apply(Project target) {
target.task('testplugin'){
doLast {
println('hello the GreetingPlugin')
}
}
}
}
apply plugin: GreetingPlugin
当插件应用于项目时,Gradle将创建插件类的实例,并调用实例的apply方法。这里我们定义了一个task任务,然后在控制台执行这个任务:
./gradlew testplugin
会输出:
> Task :testplugin
hello the GreetingPlugin
插件DSL
plugins DSL是一种新出的插件应用放肆,需要在Gradle 2.1 以上版本才可以使用。
插件DSL正在孵化(incubating)中,请注意,在以后的Gradle版本中,DSL和其它配置可能会改变。
使用就是依靠闭包代码来设置插件,比如指定Java插件:
plugins {
id 'java'
}
还有就是如果该插件已经被托管在https://plugins.gradle.org/上,就不需要配置classpath依赖了,直接使用plugins就可以使用插件:国内网差
plugins{
id "org.sonarqube" version "1.2"
}
Android Gradle 插件
分类
可根据工程类型分成一下:
- 应用程序插件:它可以生成一个可运行的apk应用,插件id为:com.android.application。
- 库插件:它可以生成AAR包给其他的APP工程公用,跟Jar一样,但是塔包含了Android资源等信息,插件id为:com.android.library。
- 测试插件:用于对其他模块进行测试,插件id为:con.android.test。
- feature插件:用于创建Android Instant App 是需要用到,插件id为:com.android.feature。
- Instant App插件:是Android Instant App 的入口,插件id为:com.android.instantapp.
编写与集成
编写
对于插件的编写,可以使用java、kotlin、groovy语言,都是基于虚拟机。这里选groovy语言编写
build.gradle中编写
第一种:就跟前面写的自定义对象插件一样,直接写在项目build.gradle里面,这种一般不推荐,很low。
buildSrc编写
第二种: 在buildSrc下编写插件。根目录下创建buildSrc
目录(或者通过创建java 模块也行),请仔细检查名字是不是对的,buildSrc是Android studio预留的命名,它会自动识别并构建的。在分别创建以下文件或目录:build.gradle
需要引入groovy的sdk,也可以指定sourceSets的目录:
//我们使用groovy来编写,引入groovy库
apply plugin: 'groovy'
//apply plugin: 'java-library'
创建src/main/groovy
目录(如果java编写,请放在java目录)
其中recources
目录是用来配置资源的,如果需要在引入包名,可以在groovy里面创建包名,之后需要在该目录下指定。在resources
目录下创建目录META-INF/gradle-plugins
目录,最后在该目录下编写插件属性文件com.hujin.plugin.properties文件。其com.hujin.plugin就是定义的包名路径,而.properties
是后缀,千万别写错了。然后在该文件中编写插件的全类名:implementation-class=com.hujin.plugin.MyTestPlugin
我们这里简单引入单个文件为例子,不处理包名。后面会以包名方式再介绍
创建一个文件,跟上面的自定义一样,实现Plugin接口的类,切记,文件一定要以.groovy
结尾,要不然就会找不到。重点:.groovy
结尾
import org.gradle.api.Project
import org.gradle.api.Plugin
class MyTestPlugin implements Plugin<Project>{
@Override
void apply(Project project) {
println('MyTestPlugin is Run')
}
}
写完之后记得同步下或者rebuild下。
在主项目的build.gradle下引入:
//包名类型的,请引入包名的字符串
apply plugin: MyTestPlugin
执行build输入完成,输出:
MyTestPlugin is Run
小问题:我遇到一个报错,但是不影响使用:
删掉buildSrc/build/libs/buildSrc.jar
包,就正常了。这个jar包属于编译产物,是可以分享的。看下种方案会介绍,或者不创建resources目录,并删掉所以build目录再同步就好了。
独立项目编写
第三种:这种方案可以发布在本地或者远程仓库,给其他人使用。另其一个工程,这里使用idea创建一个groovy工程。
然后修改build.gradle配置如下:
plugins {
id 'groovy'
}
group 'com.share.plugin'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
compile gradleApi()
compile localGroovy()
compile 'org.codehaus.groovy:groovy-all:2.3.11'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
然后跟buildSrc操作一样,在src/main/groovy
目录下创建一个包,比如创建com.hujin.plugin包,下创建ShareCustomPlugin插件。
然后需要提供一个属性文件来配置插件的位置,就是要插件properties
文件,在resources目录下,再创建一个META-INF/gradle-plugins/
目录,再创建属性文件com.hujin.plugin.properties
,写入代码:
// src/main/resources/META-INF/gradle-plugins/com.hujin.plugin.properties
implementation-class=com.hujin.plugin.ShareCustomPlugin
implementation-class属性为自定义插件的属性。编写完毕了。
集成
插件的生成
集成还是使用本地maven模式。远端参考android mac搭建Nexus3.+私有maven这个操作。
修改原build.gradle文件:引入maven库。
注意目录,有的创建项目多进或少进了一层目录../repository
和repository
plugins {
id 'groovy'
}
//引入maven库
apply plugin: 'maven'
repositories {
mavenCentral()
}
def group = 'com.hujin.plugin'
def version = '1.0.0'
def artifactId = 'myGradlePlugin'
uploadArchives{
repositories.mavenDeployer{
// 配置本地仓库路径,项目根目录下的repository目录中
repository(url: uri('repository'))
pom.groupId = group
pom.artifactId = artifactId // 项目名称(通常为类库模块名称,也可以任意)
pom.version = version
}
}
dependencies {
compile gradleApi()
compile localGroovy()
}
同步后,找到右侧Gradle侧边栏:执行uploadArchives
然后会生成本地maven文件:
而图中的myGradlePlugin-1.0.0.jar包就是我们需要的插件jar包。
远端配置完后,会到本地android项目
本地的集成
本地项目还是以android为例子,参考tools.build:gradle
的引入。
- 在根build.gradle中,引入本地maven仓库:
buildscript {
repositories {
google()
jcenter()
maven {
//这个url 是 上个项目,生成的本地maven文件,你也可以copy到本地,一样的
url 'file:/Users/apppp/IdeaProjects/CustomPluginShare/repository'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
classpath 'com.hujin.plugin:myGradlePlugin:1.0.0'
}
}
repository这个是插件项目下地址。
- 引入classpath:
classpath 'com.hujin.plugin:myGradlePlugin:1.0.0'
3.导入插件
apply plugin: 'com.hujin.plugin'
验证是否引入成功,执行 task 'assembleDebug'
,会打印出ShareCustomPlugin
的打印代码:
> Configure project :
第三方插件 ShareCustomPlugin 被调用
小结
这里还是简单的创建和使用,还没有真正的项目化。如何写一个插件,能帮助项目自动化或者便捷化,才是真正的开始。