Gradle for Androider

本文参考:

  • 深入理解Android之Gradle
  • 写给 Android 开发者的 Gradle 系列
  • Android Studio 自定义Gradle Plugin

gradle是用于构建项目的,在安卓项目中,gradle构建主要是针对.gradle文件,一个安卓项目中的.gradle文件有三种:

  • 根目录下的build.gradle:进行全局配置
  • 每一个子Moudle下的build.gradle:执行各个构建Task
  • settings.gradle:通过include函数将子Moudle的Project包含进来;

Groovy:

gradle是基于groovy语言的,groovy语言同java一样,会编译为字节码交给jvm执行,Groovy基于Java并拓展了Java,所以可以直接使用java中的规范,下面介绍一些groovy的扩展:

1. 变量定义:
 def variable1 = 1   //可以不使用分号结尾
 def varable2 = "I ama person"
 def  int x = 1  //变量定义时,也可以直接指定类型
2. 方法定义:
函数定义时,参数的类型也可以不指定。比如
String testFunction(arg1,arg2){ //无需指定参数类型
  ...
}
除了变量定义可以不指定类型外,Groovy中函数的返回值也可以是无类型的。
//无类型的函数定义,必须使用def关键字
def  nonReturnTypeFunc(){
    last_line   //最后一行代码的执行结果就是本函数的返回值
}
3. 闭包:

英文叫Closure,这是groovy中的一个数据类型,表示一段可以执行的代码,长这样:

def aClosure = {//闭包是一段代码,所以需要用花括号括起来..
    println"this is code" //这是代码,最后一句是返回值,
   //也可以使用return,和Groovy中普通函数一样
}
Closure闭包的注意点:
  • 闭包中有一个隐式参数it,类似java的this
  • 如果方法的最后一个参数式Closure类型,可以省略()

Gradle工作流程:

在了解Gradle的构建流程前,需要知道两个概念,Project,Task,每一个待编译的工程都叫做Project,每一个Project都包含了多个Task,比如Android APK的编译,可能包括Java源代码编译,资源编译,打包,签名;这些编译任务都是通过一个一个的Task完成的;

  1. Initialization:初始化阶段,Gradle 将会确定哪些项目将参与构建,并为每个项目创建一个 Project 对象实例。对于 Android 项目来说即为执行 setting.gradle 文件;

一般setting.gradle都是这样的:通过include函数将所有的Project包含进来

include ':app', ':a', ':b'
  1. Configuration:配置阶段,会解读每一个build.gradle文件,分析里面的task,然后将这些task形成一个有向图,表示task的依赖关系
task testBoth {
    println '我会在 Configuration 和 Execution 阶段都会执行'
    doFirst {
      println '我仅会在 testBoth 的 Execution 阶段执行'
    }
    doLast {
      println '我仅会在 testBoth 的 Execution 阶段执行'
    }
}

写在Task闭包的任务会在Configuration阶段运行,而doFirst,doLast会在Execution阶段运行;
切记大部分的内容是写在 doLast{} 或 doFirst{} 闭包中,因为写在如果写在 task 闭包中的话,会在 Configuration 阶段也被执行。

  1. Execution:task 的执行阶段。首先执行 doFirst {} 闭包中的内容,最后执行 doLast {} 闭包中的内容。
image

我们可以hook默认的构建过程,加入一些自定义的操作;

Project:

从上面我们可以知道每一个build.gradle都对应了一个Project对象,Project又包含了多个Task,每一个Task对应了一个构建任务;

@HasInternalProtocol
public interface Project extends Comparable, ExtensionAware, PluginAware {}

Project本质是一个Java类,可以通过Java提供的方法配置Project中的Task,因为每一个build.gradle都对应了一个具体的工程,所以需要为它指定一个插件,java工程添加java插件,安卓工程添加安卓插件:

apply plugin: 'com.android.library'
apply plugin: 'com.android.application'

使用的是apply函数,这个函数是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 options);

Task:

task是gradle中的一种数据类型,它代表了需要执行的工作,可以使用task函数创建一个Task任务;

task cleanAuraBundleFile << {
    def providedDir = new File("$project.projectDir/auraBundles/provided-bundles")
    providedDir.deleteDir()
}

<<符号是doLast的缩写
[图片上传失败...(image-88ea71-1602754294365)]

.gradle文件中包含了多个 Script Block,让我们配置相关信息,不同的SB需要配置不同的东西:

根build.gradle:
buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

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

上面的buildscript,repository,dependencies,就是SB,他们分别配置不同的信息;他们可以在Gradle DSL 学习中找到每一个解释,比如allprojects是用于配置当前 project 和所有子 project 的,该方法将会在这些 project 中执行给定的闭包;

子build.gradle:
apply plugin: 'com.android.application'  // 引入插件

android {   // android的编译,增加了一种新类型的ScriptBlock-->android

    compileSdkVersion 30
    buildToolsVersion "30.0.2"

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    //implementation表示编译和运行时候需要的jar包,fileTree是一个函数
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

子项目的.gradle文件中的SB就可以在这里找到解释Android Plugin DSL 学习

自定义Gradle Plugin

1. 在Android项目下新建一个Android library:
2. 将Module里的内容删除,只保留build.gradle文件和src/main目录,同时移除build.gradle文件里的内容,将里面内容修改为:
apply plugin: 'groovy'
apply plugin: 'maven'

dependencies{
    // gradle sdk
    compile gradleApi()
    // groovy sdk
    compile localGroovy()
    compile 'com.android.tools.build:gradle:1.5.0'
}

repositories{
    mavenCentral()
}
3 将Module里的目录修改为以下格式:

在main目录下新建groovy目录,这时候groovy文件夹会被Android识别为groovy源码目录。除了在main目录下新建groovy目录外,你还要在main目录下新建resources目录,同理resources目录会被自动识别为资源文件夹。在groovy目录下新建项目包名,就像Java包名那样。resources目录下新建文件夹META-INF,META-INF文件夹下新建gradle-plugins文件夹。这样,就完成了gradle 插件的项目的整体搭建。

4 在groovy目录下创建groovy文件
import org.gradle.api.Plugin
import org.gradle.api.Project

public class PluginImpl implements Plugin{

    void apply(Project project){
        System.out.println("========================");
        System.out.println("hello gradle plugin!");
        System.out.println("========================");
    }
}
5 声明插件名称:

在resources/META-INF/gradle-plugins目录下新建一个properties文件,注意该文件的命名就是你使用插件的名字,这里命名为sayhello.properties,文件内容引入插件的类:

implementation-class=com.myplugin.PluginImpl

那么你在其他build.gradle文件中使用自定义的插件时候则需写成:

apply plugin: 'sayhello'
6 发布插件

在Model的build.gradle文件下插入一个发布的task

uploadArchives {
    repositories {
        mavenDeployer {
            pom.groupId = 'com.myplugins'
            pom.artifactId = 'myplugins'
            pom.version = 1.3
            // maven本地仓库的目录
            repository(url: uri('../packplugin'))
        }
    }
}

sync后在右侧的Task中心可以看到这个Task:



点击上传插件后就可以在项目中看到这个插件了:


7 在项目中引入插件

注意com后面的包名和插件名需要和upload的一致;

最后在app Model下引入:

你可能感兴趣的:(Gradle for Androider)