美文网首页Android开发Android开发经验谈Android知识
Gradle入门系列(三)——初识Gradle与Project

Gradle入门系列(三)——初识Gradle与Project

作者: GitLqr | 来源:发表于2019-01-05 17:09 被阅读9次

    初识Gradle

    一、Gradle的基本概念

    一个开源的项目自动化构建工具,建立在Apache Ant和Apache Maven概念的基础上,并引入了基于Groovy的特定领域语言(DSL),而不再使用XML形式管理构建脚本。同时,gradle还是一个编程框架,可以让开发者使用编程的思想来实现应用构建。gradle的组成:

    1. groovy核心语法
    2. build script block
    3. gradle api

    二、Gradle的执行流程

    生命周期 作用
    Initialzation初始化阶段 解析整个工程中所有project(读取setting.gradle文件),构建所有的project对应的Project对象
    Configuration配置阶段 解析所有的project对象中的task,构建好所有task的拓扑图
    Execution执行阶段 执行具体的task及其依赖的task

    生命周期监听:

    // 配置阶段开始前的监听回调(即:在Initialzation与Configuration之间)
    this.beforeEvaluate {}
    // 配置阶段完成后的监听回调(即:在Configuration与Execution之间)
    this.afterEvaluate {}
    // gradle执行完毕后的回调监听(即:在Execution之后)
    this.gradle.buildFinished {}
    
    // 与 this.beforeEvaluate {} 一样
    this.gradle.beforeProject {}
    // 与 this.afterEvaluate {} 一样
    this.gradle.afterProject {}
    

    Gradle中的Project

    一、Idea与Gradle 对于project概念的区别

    在Idea中,一个项目就是Project,一个Project下可以包含多个模块(Module),一个Module下,又可以有多个Module,其树状结构如下:

    虽然可以在Module中继续创建子Module,但一般情况下,我们不会这么做,最多就两层。

    +Project
    --+Module
    ----+Module
    ----+Module
    --+Module
    --+Module
    

    而对于Gradle而言,Idea中的无论是Project还是Module,都是project,故树状结构如下:

    每个project下,都一定会有一个build.gradle

    +project        // rootProject
    --+project      // subProject
    ----+project
    ----+project
    --+project
    --+project
    

    二、project相关api

    api 作用
    getAllprojects() 获取工程中所有的project(包括根project与子project)
    getSubProjects() 获取当前project下,所有的子project(在不同的project下调用,结果会不一样,可能返回null)
    getParent() 获取当前project的父project(若在rooProject的build.gradle调用,则返回null)
    getRootProject() 获取项目的根project(一定不会为null)
    project(String path, Closure configureClosure) 根据path找到project,通过闭包进行配置(闭包的参数是path对应的Project对象)
    allprojects(Closure configureClosure) 配置当前project和其子project的所有project
    subprojects(Closure configureClosure) 配置子project的所有project(不包含当前project)
    // rootProject build.gradle下配置:
    // 1、Project project(String path, Closure configureClosure);
    project('app') { Project project ->       // 一个参数时,可以省略不写,这里只是为了明确参数的类型
      apply plugin : 'com.android.application'
      group 'com.lqr'
      version '1.0.0-release'
      dependencies {}
      android {}
    }
    
    // 2、allprojects(Closure configureClosure)
    allprojects {
      group 'com.lqr'
      version '1.0.0-release'
    }
    
    // 3、subprojects(Closure configureClosure)
    subprojects { Project project -> 
      if(project.plugins.hasPlugin('com.android.library')){
        apply from: '../publishToMaven.gradle'
      }
    }
    

    三、属性相关api

    1、在gradle脚本文件中使用ext块扩展属性

    父project中通过ext块定义的属性,子project可以直接访问使用

    // rootProject : build.gradle
    // 定义扩展属性
    ext {
      compileSdkVersion = 25
      libAndroidDesign = 'com.android.support:design:25.0.0'
    }
    
    // app : build.gradle
    android {
      compileSdkVersion = this.compileSdkVersion // 父project中的属性,子project可以直接访问使用
      ...
    }
    dependencies {
      compile this.libAndroidDesign // 也可以使用:this.rootproject.libAndroidDesign
      ...
    }
    
    

    2、在gradle.properties文件中扩展属性

    hasProperty('xxx'):判断是否有在gradle.properties文件定义xxx属性。
    在gradle.properties中定义的属性,可以直接访问,但得到的类型为Object,一般需要通过toXXX()方法转型。

    // gradle.properties
    // 定义扩展属性
    isLoadTest=true
    mCompileSdkVersion=25
    
    // setting.gradle
    // 判断是否需要引入Test这个Module
    if(hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) {
      include ':Test'
    }
    
    // app : build.gradle
    android {
      compileSdkVersion = mCompileSdkVersion.toInteger()
      ...
    }
    

    四、文件相关api

    api 作用
    getRootDir() 获取rootProject目录
    getBuildDir() 获取当前project的build目录(每个project都有自己的build目录)
    getProjectDir() 获取当前project目录
    File file(Object path) 定位一个文件,相对于当前project开始查找
    ConfigurableFileCollection files(Object... paths) 定位多个文件,与file类似
    copy(Closure closure) 拷贝文件
    fileTree(Object baseDir, Closure configureClosure) 定位一个文件树(目录+文件),可对文件树进行遍历
    // 打印common.gradle文件内容
    println getContent('common.gradle')
    def getContent(String path){
      try{
        def file = file(path)
        return file.text
      }catch(GradleException e){
        println 'file not found..'
      }
      return null
    }
    
    // 拷贝文件、文件夹
    copy {
      from file('build/outputs/apk/')
      into getRootProject().getBuildDir().path + '/apk/'
      exclude {} // 排除文件
      rename {} // 文件重命名
    }
    
    // 对文件树进行遍历并拷贝
    fileTree('build/outputs/apk/') { FileTree fileTree ->
        fileTree.visit { FileTreeElement element ->
            println 'the file name is: '+element.file.name
            copy {
                from element.file
                into getRootProject().getBuildDir().path + '/test/'
            }
        }
    }
    

    五、依赖相关api

    配置工程仓库及gradle插件依赖

    // rootProject : build.gradle
    buildscript { ScriptHandler scriptHandler ->
        // 配置工程仓库地址
        scriptHandler.repositories { RepositoryHandler repositoryHandler ->
            repositoryHandler.jcenter()
            repositoryHandler.mavenCentral()
            repositoryHandler.mavenLocal()
            repositoryHandler.ivy {}
            repositoryHandler.maven { MavenArtifactRepository mavenArtifactRepository ->
                mavenArtifactRepository.name 'personal'
                mavenArtifactRepository.url 'http://localhost:8081/nexus/repositories/'
                mavenArtifactRepository.credentials {
                    username = 'admin'
                    password = 'admin123'
                }
            }
        }
        // 配置工程的"插件"(编写gradle脚本使用的第三方库)依赖地址
        scriptHandler.dependencies {
            classpath 'com.android.tools.build:gradle:2.2.2'
            classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'
        }
    }
    
    // ============ 上述脚本简化后 ============
    
    buildscript {
        // 配置工程仓库地址
        repositories {
            jcenter()
            mavenCentral()
            mavenLocal()
            ivy {}
            maven {
                name 'personal'
                url 'http://localhost:8081/nexus/repositories/'
                credentials {
                    username = 'admin'
                    password = 'admin123'
                }
            }
        }
        // 配置工程的"插件"(编写gradle脚本使用的第三方库)依赖地址
        dependencies {
            classpath 'com.android.tools.build:gradle:2.2.2'
            classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'
        }
    }
    

    配置应用程序第三方库依赖

    compile: 编译依赖包并将依赖包中的类打包进apk。
    provided: 只提供编译支持,但打包时依赖包中的类不会写入apk。

    // app : build.gradle
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar']) // 依赖文件树
        // compile file() // 依赖单个文件
        // compile files() // 依赖多个文件
        compile 'com.android.support:appcompat-v7:26.1.0' // 依赖仓库中的第三方库(即:远程库)
        compile project('mySDK') { // 依赖工程下其他Module(即:源码库工程)
          exclude module: 'support-v4' // 排除依赖:排除指定module
          exclude group: 'com.android.support' // 排除依赖:排除指定group下所有的module
          transitive false // 禁止传递依赖,默认值为false
        }
      
        // 栈内编译
        provided('com.tencent.tinker:tinker-android-anno:1.9.1')
    }
    

    provided的使用场景:

    1. 依赖包只在编译期起作用。(如:tinker的tinker-android-anno只用于在编译期生成Application,并不需要把该库中类打包进apk,这样可以减小apk包体积)
    2. 被依赖的工程中已经有了相同版本的第三方库,为了避免重复引用,可以使用provided。

    六、外部命令api

    // copyApk任务:用于将app工程生成出来apk目录及文件拷贝到本机下载目录
    task('copyApk') {
        doLast {
            // gradle的执行阶段去执行
            def sourcePath = this.buildDir.path + '/outputs/apk'
            def destinationPath = '/Users/lqr/Downloads'
            def command = "mv -f ${sourcePath} ${destinationPath}"
            // exec块代码基本是固定的
            exec {
                try {
                    executable 'bash'
                    args '-c', command
                    println 'the command is executed success.'
                }catch (GradleException e){
                    println 'the command is executed failed.'
                }
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:Gradle入门系列(三)——初识Gradle与Project

        本文链接:https://www.haomeiwen.com/subject/uycdrqtx.html