Gradle学习笔记

作者: KevinLive | 来源:发表于2017-06-13 15:06 被阅读135次
    GradleGradle

    原文地址:LoveDev

    Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的XML

    在 Android 项目中每一个 Project 必须设置一个 build.gradle 文件,对于 multi-projects build,需要在根目录也放一个 build.gradle,和一个 setting.gradle

    • build.gradle 用来配置其他子 Project
    • setting.gradle 用来告诉 Gradle 这个 multi-projects 包含多少个子 project,也可以定义一些函数做一些初始化的工作

    一个 Project 有多少个 Task,有编译脚本指定的插件而决定,插件是用来定义 Task,并具体执行 Task 的东西

    工程信息

    查看工程信息:

    $ cd rootProject
    $ ./gradlew projects
    
    工程信息工程信息

    Task

    从上图中最后一段文字可以看出怎么查看一个工程中的 Task 列表:

    $ ./gradlew :app:tasks
    
    # 或者下面的方式也可以
    $ cd app
    $ ./gradlew tasks
    
    Task 信息Task 信息

    通过每个 Task 的描述,大概知道每个 Task 的作用,执行每个 Task 也非常简单:

    $ ./gradlew taskName
    
    # 举个栗子
    $ ./gradlew assembleDebug
    

    从图中可以看出执行assembleDebug的 Task之后,会先执行其他一些 Task,这是因为 Task 之间有依赖关系,我们可以添加自定义的 Task,并指定 Task 依赖它实现想要的功能

    Gradle 工作流程

    • Gradle 开始初始化,setting.gradle 开始执行
    • 进入配置阶段,每个 Project 会被解析,内部任务会被添加到一个有向图里,用于解决过程中的依赖关系
    • 最后执行阶段,执行指定的 Task,以及其依赖的 Task

    Gradle 三种对象

    Gradle 主要有三种对象,分别对应三种不同的脚本文件:

    • Gradle 对象:Gradle 从默认的配置脚本中构造出一个 Gradle 对象
    • Project 对象:每个 build.gradle 脚本会转换成一个 Project 对象
    • Setting 对象:每个 setting.gradle 脚本会转换成一个 Setting 对象

    在根目录的build.gradle和setting.gradle中分别添加如下代码:

    // setting.gradle 中修改为 In setting
    println "In LoveDev, gradle id is " +gradle.hashCode()  
    println "Home Dir:" + gradle.gradleHomeDir  
    println "User Home Dir:" + gradle.gradleUserHomeDir  
    println "Parent: " + gradle.parent  
    

    可以看到两个 gradle 对象的 hash 值都是一样的,gradle.gradleHomeDir 是 Gradle 具体的可执行程序目录,gradle.gradleUserHomeDir 是用户的 Gradle 根目录,用于缓存下载的资源,构建脚本等等

    设置属性

    如果项目中只有单个 build.gradle,不用考虑属性的跨脚本传播,但是一个正常的项目不止一个 build.gradle,Gradle 提供了一种额外属性(extra property)的方法,第一次定义该属性的时候,需要通过 ext 前缀标识它是一个额外的属性,定义完之后再进行存取就不需要 ext 前缀了,Project 和 Gradle 对象都可以设置 ext 属性,在 setting.gradle 中定义一个额外属性:

    include ':app', ':model', ':baseLibrary'
    
    println "In setting, gradle id is " +gradle.hashCode()
    println "Home Dir:" + gradle.gradleHomeDir
    println "User Home Dir:" + gradle.gradleUserHomeDir
    println "Parent: " + gradle.parent
    
    // initGradleEnvironment 方法读取local.properties文件中的属性,并设置为额外属性
    
    def initGradleEnvironment(){
        // 从local.properites中读取
        Properties properties = new Properties()
        File propertyFile = new File(rootDir.getAbsolutePath() +"/local.properties")
        properties.load(propertyFile.newDataInputStream())
        
        //第一次定义时需要ext前缀
        gradle.ext.kevin =properties.getProperty('kevin')
    
        // 再次存取api的时候,就不需要ext前缀
        println "extra property: " + gradle.kevin  
    }
    
    // 执行方法
    initGradleEnvironment()
    

    这样设置之后,在根目录的 build.gradle 文件中也可以访问到该属性:

    // 添加这行代码就可以直接访问
    println "extra property: " + gradle.kevin
    

    实例

    讲了这么多,下面列举几个常见的 Gradle 配置:

    加速Gradle构建

    阿里国内镜像,下载速度很快,从此告别添加依赖后再等上十分钟

    allprojects {
        repositories {
            maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
        }
    }
    

    修改默认 apk 文件名

    很多时候需要通过 apk 的命名很直观的看到一些信息,比如版本号,渠道以及是否测试版等等,此时就需要修改 apk 文件名:

    buildTypes {
        ...
        
         applicationVariants.all { variant ->
                        variant.outputs.each { output ->
                            def outputFile = output.outputFile
                            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                                // 输出apk名称为LoveDev-v1.0.apk
                                def fileName = "LoveDev-v${defaultConfig.versionName}.apk"
                                output.outputFile = new File(outputFile.parent, fileName)
                            }
                        }
                    }
        ...
    }
    

    productFlavors 配置产品风味

    如果除了正式版,测试版之外还要继续细分化,针对不同的渠道,正式版要分为收费版,免费版等情况,这时候就需要用到 productFlavors 来配置了

    将配置信息添加到 productFlavors {} 代码块并配置想要的设置。产品风味支持与 defaultConfig 相同的属性,这是因为 defaultConfig 实际上属于 ProductFlavor 类,我在实际项目中碰到一个需求,针对某一个功能方法,分为两个版本处理,除此之外在 CI 环境中还要同时上传这两个版本,这就意味着两个版本的包名也要不同,下面是示例代码:

    // buildConfig 中配置AUDIO_VERSION字段
    productFlavors {
        shine {
         buildConfigField "int", "AUDIO_VERSION", "2"
         versionCode 2
        }
        webrtc {
         buildConfigField "int", "AUDIO_VERSION", "1"
         versionCode 1
        }
    }
      
    // buildTypes 针对不同的产品风味,构建不同的 apk 文件名
    buildTypes {
        ...
        
         applicationVariants.all { variant ->
                        variant.outputs.each { output ->
                            def outputFile = output.outputFile
                            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                                // 这里添加productFlavors的名字,输出apk名称为LoveDev-v1.0-webrtc.apk
                                def fileName = "LoveDev-v${defaultConfig.versionName}-${variant.productFlavors[0].name}.apk"
                                output.outputFile = new File(outputFile.parent, fileName)
                            }
                        }
                    }
        ...
    }
    

    配置之后在 buildType 类中就有了int 类型的 AUDIO_VERSION 字段,可以根据该字段判断方法中的具体实现

    其实很多配置,在官网里面已经提到过了,不过还是要根据具体的项目进行具体的配置,尽量不要照抄照搬,官网地址请戳这里

    相关文章

      网友评论

        本文标题:Gradle学习笔记

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