文章目录
- Gradle插件
- 一、Java Gradle插件
- 二、Android Gradle插件
- 2.1、应用Android Gradle插件
- 三、自定义Gradle插件
- 3.1、Build script
- 3.2、buildSrc project
- 3.3、Standalone project
- 四、源码地址
- 五、资料
Gradle插件
Gradle
可以认为是一个框架,负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译 Java
有 Java
插件,编译 Groovy
有 Groovy
插件,编译 Android APP
有 Android APP
插件,编译 Android Library
有 Android 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 Gradle
和Android Studio
完美无缝搭配的新一代构建系统。
- APP插件id :
com.android.application
- Library插件id:
com.android.library
- Test插件id:
com.android.test
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
(注:文章编写时间较早,目前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: 默认配置,它是一个
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插件
编写自定义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
目录下新建了一个插件类,如下:
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 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.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,并依赖于CustomPluginTask
。CustomPluginTask
中定义了一个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'
最终的文件如下:
插件编写完成后,在Android Studio
的右上角打开Gradle
,执行:plugin
分组中的publish
命令,执行完成后,会在项目根目录下生成repo
仓库:
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
执行writeToFile
的task
输出了我们写入的文本,再看看build
目录下是否有我们想要的文件:
可以看到在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