//root build.gradle
 println “project.root start”
 buildscript {
 repositories {
 }
 dependencies {
 }
 }allprojects {
 }
 println “project.root end”//app build.gradle
 println “project.app start”
 project.afterEvaluate {
 println “project.app.afterEvaluate print”
 }
 project.beforeEvaluate {
 println “project.app.beforeEvaluate print”
 }
 println “project.app end”如果是mac/linux,执行./gradlew 得到如下结果:
settings.gradle start
 settings.gradle endConfigure project :
 project.root start
 project.root endConfigure project :app
 project.app start
 project.app end
 project.app.afterEvaluate print
dencies {
 }
 }allprojects {
 }
 println “project.root end”//app build.gradle
 println “project.app start”
 project.afterEvaluate {
 println “project.app.afterEvaluate print”
 }
 project.beforeEvaluate {
 println “project.app.beforeEvaluate print”
 }
 println “project.app end”如果是mac/linux,执行./gradlew 得到如下结果:
settings.gradle start
 settings.gradle endConfigure project :
 project.root start
 project.root endConfigure project :app
 project.app start
 project.app end
 project.app.afterEvaluate print

Groovy 语法

下面讲一些关于groovy的语法,可以打开Android Studio Tools-> Groovy Console练习Groovy 语法 ,如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FYYIlSuy-1636556815212)(https://user-gold-cdn.xitu.io/2019/9/17/16d3e0773023df7a?imageView2/0/w/1280/h/960/ignore-error/1)]

可选的类型定义,可以省略语句结束符分号(;)
int vs = 1
 def version = ‘version1’println(vs)
 println(version)括号也是可选的
println vs
 println version字符串定义
def s1 = ‘aaa’
 def s2 = “version is ${version}”
 def s3 = ‘’’ str
 is
 many
 ‘’’
 println s1
 println s2
 println s3集合
def list = [‘ant’,‘maven’]
 list << “gradle”
 list.add(‘test’)
 println list.size()
 println list.toString()
 //map
 def years = [‘key1’:1000,“key2”:2000]
 println years.key1
 println years.getClass()输出结果
[ant, maven, gradle, test]
 1000
 class java.util.LinkedHashMap

闭包

groovy语法中支持闭包语法,闭包简单的说就是代码块,如下:

def v = {
 v -> println v
 }
 static def testMethod(Closure closure){
 closure(‘闭包 test’)
 }
 testMethod v

其中定义的v就为闭包,testMethod 为一个方法,传入参数为闭包,然后调用闭包.

解释 apply plugin: 'xxxx’和 dependencies{}

准备工作,看gradle的源码

我们先把子项目的build.gradle改为如下形式

apply plugin: ‘java-library’
 repositories {
 mavenLocal()
 }
 dependencies {
 compile gradleApi()
 }

这样,我们就可以直接看gradle的源码了,在External Libraries里如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vg7Qe6nR-1636556815233)(https://user-gold-cdn.xitu.io/2019/9/17/16d3e2c252afef49?imageView2/0/w/1280/h/960/ignore-error/1)]

解释

进入build.gradle 点击apply 会进入到gradle的源码,可以看到
//PluginAware
 /**• Applies a plugin or script, using the given options provided as a map. Does nothing if the plugin has already been applied.
•  
• The given map is applied as a series of method calls to a newly created {@link ObjectConfigurationAction}.
• That is, each key in the map is expected to be the name of a method {@link ObjectConfigurationAction} and the value to be compatible arguments to that method.
• 
• The following options are available:
• 
• {@code from}: A script to apply. Accepts any path supported by {@link org.gradle.api.Project#uri(Object)}.
• 
• 
• {@code plugin}: The id or implementation class of the plugin to apply.
• 
• 
• {@code to}: The target delegate object or objects. The default is this plugin aware object. Use this to configure objects other than this object.
• 
• @param options the options to use to configure and {@link ObjectConfigurationAction} before “executing” it
 */
 void apply(Map<String, ?> options);• 用Groovy 语法很清楚的解释,apply其实就是一个方法,后面传递的就是一个map,其中plugin为key.
那么dependencies{}也是一样
//Project
 /**• Configures the dependencies for this project. 
• 
• This method executes the given closure against the {@link DependencyHandler} for this project. The {@link 
• DependencyHandler} is passed to the closure as the closure’s delegate.
• 
Examples:
• See docs for {@link DependencyHandler}
• 
• @param configureClosure the closure to use to configure the dependencies.
 */
 void dependencies(Closure configureClosure);

dependencies是一个方法 后面传递的是一个闭包的参数.

问题:思考那么android {}也是一样的实现吗? 后面讲解

Gradle Project/Task

在前面章节中提到gralde初始化配置,是先解析并执行setting.gradle,然后在解析执行build.gradle,那么其实这些build.gradle 就是Project,外层的build.gradle是根Project,内层的为子project,根project只能有一个,子project可以有多个.

我们知道了最基础的gradle配置,那么怎么来使用Gradle里面的一些东西来为我们服务呢?

Plugin

前面提到apply plugin:‘xxxx’,这些plugin都是按照gradle规范来实现的,有java的有Android的,那么我们来实现一个自己的plugin.

把build.gradle 改为如下代码

//app build.gradle
 class LibPlugin implements Plugin{
 @Override
 void apply(Project target) {
 println ‘this is lib plugin’
 }
 }
 apply plugin:LibPlugin

运行./gradlew 结果如下

Configure project :app
 this is lib plugin

Plugin 之Extension

我们在自定义的Plugin中要获取Project的配置,可以通过Project去获取一些基本配置信息,那我们要自定义的一些属性怎么去配置获取呢,这时就需要创建Extension了,把上述代码改为如下形式。

//app build.gradle
 class LibExtension{
 String version
 String message
 }
 class LibPlugin implements Plugin{
 @Override
 void apply(Project target) {
 println ‘this is lib plugin’
 //创建 Extension
 target.extensions.create(‘libConfig’,LibExtension)
 //创建一个task
 target.tasks.create(‘libTask’,{
 doLast{
 LibExtension config = project.libConfig
 println config.version
 println config.message
 }
 })
 }
 }
 apply plugin:LibPlugin
 //配置
 libConfig {
 version = ‘1.0’
 message = ‘lib message’
 }

配置完成后,执行./gradlew libTask 得到如下结果

Configure project :app
 this is lib plugin
 Task :lib:libTask
 1.0
 lib message

看完上述代码,我们就知道android {} 其实他就是一个Extension, 他是由plugin ‘com.android.application’或者’com.android.library’ 创建。

Task

上述代码中,创建了一个名字为libTask的task,gradle中创建task的方式由很多中, 具体的创建接口在TaskContainer类中

//TaskContainer
 Task create(Map<String, ?> options) throws InvalidUserDataException;
 Task create(Map<String, ?> options, Closure configureClosure) throws InvalidUserDataException;
 Task create(String name, Closure configureClosure) throws InvalidUserDataException;
 Task create(String name) throws InvalidUserDataException;
 T create(String name, Class type) throws InvalidUserDataException;
 T create(String name, Class type, Action<? super T> configuration) throws InvalidUserDataException;

Project不可以执行跑起来,那么我们就要定义一些task来完成我们的编译,运行,打包等。com.android.application插件 为我们定义了打包task如assemble,我们刚才定义的插件为我们添加了一个libTask用于输出。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DDm8Jn7E-1636556815234)(https://user-gold-cdn.xitu.io/2019/9/17/16d3e77fc9cc60ff?imageView2/0/w/1280/h/960/ignore-error/1)]

Task API

我们看到创建的task里面可以直接调用doLast API,那是因为Task类中有doLast API,可以查看对应的代码看到对应的API

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KnXQeAQ3-1636556815236)(https://user-gold-cdn.xitu.io/2019/9/17/16d3e818c3dbb8c5?imageView2/0/w/1280/h/960/ignore-error/1)]

Gradle的一些Task

gradle 为我们定义了一些常见的task,如clean,copy等,这些task可以直接使用name创建,如下:

task clean(type: Delete) {
 delete rootProject.buildDir
 }

依赖task

我们知道Android打包时,会使用assemble相关的task,但是仅仅他是不能直接打包的,他会依赖其他的一些task. 那么怎么创建一个依赖的Task呢?代码如下

task A{
 println “A task”
 }
 task B({
 println ‘B task’
 },dependsOn: A)执行./graldew B 输出
A task
 B task

自定义一个重命名APP名字的插件

通过上述的一些入门讲解,大概知道了gradle是怎么构建的,那现在来自定义一个安卓打包过程中,重命名APP名字的一个插件。

上述在build.gradle直接编写Plugin是OK的,那么为了复用性更高一些,那我们怎么把这个抽出去呢?

如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VMPybZLi-1636556815236)(https://user-gold-cdn.xitu.io/2019/9/17/16d3e91b752658ef?imageView2/0/w/1280/h/960/ignore-error/1)]

其中build.gradle为

apply plugin: ‘groovy’
 apply plugin: ‘maven’
 repositories {
 mavenLocal()
 jcenter()
 }dependencies {
 compile gradleApi()
 }def versionName = “0.0.1”
 group “com.ding.demo”
 version versionName
 uploadArchives{ //当前项目可以发布到本地文件夹中
 repositories {
 mavenDeployer {
 repository(url: uri(’…/repo’)) //定义本地maven仓库的地址
 }
 }
 }apkname.properties为
implementation-class=com.ding.demo.ApkChangeNamePlugin
ApkChangeNamePlugin
package com.ding.demo
import org.gradle.api.Project
 import org.gradle.api.Pluginclass ApkChangeNamePlugin implements Plugin{
static class ChangeAppNameConfig{
 String prefixName
 String notConfig
 }static def buildTime() {
 return new Date().format(“yyyy_MM_dd_HH_mm_ss”, TimeZone.getTimeZone(“GMT+8”))
 }@Override
 void apply(Project project) {
 if(!project.android){
 throw new IllegalStateException(‘Must apply ‘com.android.application’ or ‘com.android.library’ first!’);
 }
 project.getExtensions().create(“nameConfig”,ChangeAppNameConfig)
 ChangeAppNameConfig config
 project.afterEvaluate {
 config = project.nameConfig
 }
 project.android.applicationVariants.all{
 variant ->
 variant.outputs.all {
 output ->
 if (output.outputFile != null && output.outputFile.name.endsWith(’.apk’)
 && !output.outputFile.name.contains(config.notConfig)) {
 def appName = config.prefixName
 def time = buildTime()
 String name = output.baseName
 name = name.replaceAll("-", “_”)
 outputFileName = “{variant.versionCode}-{time}.apk”
 }
 }
 }
 }
 }

定义完成后,执行./gradlew uploadArchives 会在本目录生成对应对应的插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Z5g0rLc-1636556815237)(https://user-gold-cdn.xitu.io/2019/9/17/16d3e94decfb19ed?imageView2/0/w/1280/h/960/ignore-error/1)]

应用插件 在根build.gralde 配置

buildscript {
 repositories {
 maven {url uri(’./repo/’)}
 google()
 jcenter()
 }
 dependencies {
 classpath ‘com.android.tools.build:gradle:3.4.1’
 classpath ‘com.ding.demo:apkname:0.0.1’
 }
 }在app.gralde 设置
apply plugin: ‘apkname’
 nameConfig{
 prefixName = ‘demo’
 notConfig = ‘debug’
 }

Gradle doc 官网

Gradle的基础API差不多就介绍完了。

官网地址:docs.gradle.org/current/use… 可以去查看对应的API,也可以直接通过源码的方式查看

但是笔记还没完,学习了Gradle的基础,我们要让其为我们服务。下面介绍几个实际应用.

APT 技术


APT 全称Annotation Processing Tool,编译期解析注解,生成代码的一种技术。常用一些IOC框架的实现原理都是它,著名的ButterKnife,Dagger2就是用此技术实现的,SpringBoot中一些注入也是使用他进行注入的.

pkname’
 nameConfig{
 prefixName = ‘demo’
 notConfig = ‘debug’
 }

Gradle doc 官网

Gradle的基础API差不多就介绍完了。

官网地址:docs.gradle.org/current/use… 可以去查看对应的API,也可以直接通过源码的方式查看

但是笔记还没完,学习了Gradle的基础,我们要让其为我们服务。下面介绍几个实际应用.

APT 技术


APT 全称Annotation Processing Tool,编译期解析注解,生成代码的一种技术。常用一些IOC框架的实现原理都是它,著名的ButterKnife,Dagger2就是用此技术实现的,SpringBoot中一些注入也是使用他进行注入的.