• Gradle打包工具入门


    1、Gradle介绍

    Gradle是一种自动化构建语言,是一种DSL。目前是Android的默认构建工具,是一个编程框架

    Gradle是一个基于Apache AntApache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,也增加了基于Kotlin语言的kotlin-based DSL,抛弃了基于XML的各种繁琐配置

    特点:

    • 支持局部构建和增量构建
    • 对多工程的构建支持很出色,工程依赖是gradle的第一公民
    • 是第一个构建集成工具,与antmavenivy有良好的相容相关性
    • gradle的整体设计是以作为一种语言为导向的,而非成为一个严格死板的框架
    • 支持多方式依赖管理:包括从maven远程仓库、nexus私服、ivy仓库以及本地文件系统的jars或者dirs
    • 轻松迁移:gradle适用于任何结构的工程,你可以在同一个开发平台平行构建原工程和gradle工程。通常要求写相关测试,以保证开发的插件的相似性,这种迁移可以减少破坏性,尽可能的可靠。这也是重构的最佳实践

    2、Gradle配置分析

    2.1 根目录配置

    • settings.gradle

    在代码编译时最先找到这个文件

    apply from: 'allconfig.gradle'
    include: 'app'  // 包含的工程模块
    if(buildType==1){
        include ':mylibrary2'
    }else if(buildType==2){
        include ':mylibrary'
    }
    //在这里写一个脚本,让编译速度更快
    rootProject.name = 'gradledemo'  // 工程名
    
    • build.gradle
    // 根目录的构建脚本
    buildscript {
        // 指定了仓库
        repositories {
            maven {  // 加速地址要放在最上面,从上往下找
                url 'http://maven.aliyun.com/nexus/content/groups/public/'
            }
            google()
            jcenter()
        }
        dependencies {  // 配置插件
            // gradle 插件版本
            classpath "com.android.tools.build:gradle:4.0.1"
        }
    }
    
    allprojects {
        // 项目本身需要的依赖,配置所有的Module公共依赖
        repositories {
            maven {
                url 'http://maven.aliyun.com/nexus/content/groups/public/'
            }
            google()
            jcenter()
        }
    }
    
    // 任务
    task Clean(type: Delete) {
        delete rootProject.buildDir // 清理每次编译生成的文件
    }
    

    2.2 应用目录配置

    • build.gradle
    // 配置当前Module的属性
    // 如果声明的是com.android.library  表示是一个依赖库
    // 如果声明的是com.android.plugin   表示是一个插件
    // 如果声明的是com.android.application   表示是一个app
    apply plugin: 'com.android.application'
    // 类似引入包一样,引入外部的gradle配置文件
    apply from: 'config.gradle'
    
    android {
        compileSdkVersion 30
        buildToolsVersion "30.0.2"
    
        defaultConfig {
            applicationId "com.mn.gradledemo"
            minSdkVersion 16
            targetSdkVersion 30
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndridJunitRunner"
        }
    
        dependencies {
            implementation fileTree(dir: "libs", include: ["*.jar"])
            implementation 'androidx.appcompat:appcompat:1.2.0'
            implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
            testImplementation 'junit:junit:4.12'
            androidtestInstrumentation 'androidx.test.ext:junit:1.1.2'
            androidtestInstrumentation 'androidx.test.espresso:espresso-core:3.3.0'
        }
    }
    
    // 只要声明了一个任务,不用调用就会执行
    task stringText{
        // 使用def声明关键字
        def str1 = "shuanyinhao";
        def str2 = 'danyinhan';
        println("${str1}---${str2}")
    }
    
    • config.gradle
    // ext就表示额外的属性声明
    ext{
        server = "prod"
        dataSource = "0"
    }
    

    3、Gradle基础语法

    3.1 常规语法

    // list
    task list{
        def list=[1,2,3,4,5,6]
        def weekList = ['one','two','three']
        println(list[0])
        println(weekList[0])
        for(int i in 1..10){
            println i
        }
        // 这里的it就表示每一个元素, it是一个关键字,表示它自己
        weekList.each {
            println it
        }
    }
    
    // map
    task map{
        def map:['name':'jack','age':19]
        println map['name']
        map.each {
            println "key:${it.key},value:${it.value}"
        }
        println(methodA(2,3)) // 5
    }
    
    // 在gradle语法当中,定义一个方法
    // 如果在没有return的情况下,函数默认会返回最后一行非空的值
    def methodA(int a,int b){
        a+b
    }
    
    // 怎样定义一个对象
    task javaBeanTask{
        Student student = new Student()
        student.name = "Lily"
        student.age = 19
        println student.name + "---${student.age}"
        println student.getName() + "---${student.getAge()}"
    }
    
    class Student{
        String name
        int age
    
        String getName(){
            return name
        }
    
        void setName(String name){
            this.name = name
        }
    
        int getAge(){
            return age
        }
    
        void setAge(int age){
            this.age = age
        }
    }
    

    3.2 闭包和it关键字

    Groovy中的闭包是一个开放,匿名的代码块,可以接受参数,返回值并赋值给变量

    闭包,是一个代码块,或可以理解成一个匿名函数,在外部方法调用时,可以将其作为方法的实参传递给方法的形参,并在方法内部回调此匿名函数,且回调此匿名函数时可以传递实参给到匿名函数的内部去接收,并执行此匿名函数

    同时,此代码块或匿名函数也可以赋值给一个变量,使其具有自执行的能力,且最后一行的执行语句作为匿名函数的返回

    // 闭包,自定义闭包
    def mEach(closure){
        for(int i in 1..5){
            closure(i)
        }
    }
    
    def mEachWithParams(closure){
        def map = ['name':'groovy','age':10]
        map.each{
            closure(it.key,it.value)
        }
    }
    
    // 调用闭包
    task closureTask{
        // 回调一个参数的时候,it就是指这个参数,就能用it,多个就不行了
        mEach({
            println it
            // a->println a
        })
        mEachWithParams{
            m,n—>println "${m} is ${n}"
        }
    }
    

    4、环境区分

    主要目的是不需要修改代码就能区分测试环境和生产环境

    例如有这样的代码目录(不同环境的配置文件)

    app/src/main/filters/debug/config.properties
    app/src/main/filters/release/config.properties
    

    通过读取文件流实现按不同环境区分

    • build.gradle
    // 配置当前Module的属性
    // 如果声明的是com.android.library  表示是一个依赖库
    // 如果声明的是com.android.plugin   表示是一个插件
    // 如果声明的是com.android.application   表示是一个app
    apply plugin: 'com.android.application'
    // 类似引入包一样,引入外部的gradle配置文件
    apply from: 'config.gradle'
    
    android {
    ...
    
        // 构建类型
        buildTypes{
            // 测试环境
            debug{
                // 参数: 声明的类型、名字、属性值
                buildConfigField 'String','SERVER2',getServer2('debug')
            }
            release{
                buildConfigField 'String','SERVER2',getServer2('release')
            }
        }
    }
    
    // 读取文件流,str代表debug还是release
    def getServer2(String str){
        def SERVER2
        Properties properties = new Properties();
        // 相对路径
        def proFile = file("src/main/filters/"+str+"/config.properties")
        if(proFile.canRead()){
            properties.load(new FileInputStream(proFile))
            if(properties!=null){
                SERVER2 = properties['SERVER2']
            }
        }
        return SERVER2
    }
    

    5、多渠道打包

    多渠道打包常用于安卓app,例如统计不同渠道的数据(投放到多个应用市场)

    5.1 核心逻辑

    主要核心实现如下

    apply plugin: 'com.android.application'
    apply from: 'config.gradle'
    
    android {
        compileSdkVersion 30
        buildToolsVersion "30.0.2"
    
        defaultConfig {
            applicationId "com.mn.gradledemo"
            minSdkVersion 16
            targetSdkVersion 30
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndridJunitRunner"
            // 多渠道打包
            flavorDimensions "versionCode"
        }
    ...
    
        // 构建类型
        buildTypes{
            // 测试环境
            debug{
                // 参数: 声明的类型、名字、属性值
                buildConfigField 'String','SERVER2',getServer2('debug')
                android.applicationVariants.all{
                    variant ->
                        variant.outputs.all{
                            def fileName = "${getCurrentTime()}_V{defaultConfig.versionName}_debug.apk"
                            outputFileName = fileName
                        }
                }
            }
            release{
                buildConfigField 'String','SERVER2',getServer2('release')
            }
        }
    
        // 多渠道打包
        productFlavors{
            xiaomi{
                buildConfigField 'String','PLATE_FORM',"\"xiaomi\""
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
            }
            yinyongbao{
                buildConfigField 'String','PLATE_FORM',"\"yingyongbao\""
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"]
            }
        }
    }
    
    static def getCurrentTime(){
        return new Date().format("yyyy-MM-dd",timeZone.getTimeZone("UTC"))
    }
    

    5.2 一键化配置多渠道打包

        // 一键化多渠道打包
        productFlavors{
            xiaomi{}
            yingyongbao{}
        }
        productFlavors.all{
            flavor ->
                flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
                buildConfigField 'String','PLATE_FORM',"\"${name}\""
        }
    

    6、gradle打包加速

    maven打包一样,gradle会在编译时的用户家目录,例如/root/.gradle目录下生成一个缓存目录,除此之外,在应用的目录下也会生成一个build目录,这个目录下也有相应的build cache

    可以在全局配置gradle,使其拉取插件时走国内的源

    配置文件为/root/.gradle/init.gradle,内容如下

    allprojects {
        repositories {
            mavenLocal()
    		maven { name "Aliyun" ; url "https://maven.aliyun.com/repository/public" }
    		maven { name "Bstek" ; url "http://nexus.bsdn.org/content/groups/public/" }
        }
    
    	buildscript { 
    		repositories { 
    			maven { name "Aliyun" ; url 'https://maven.aliyun.com/repository/public' }
    			maven { name "Bstek" ; url 'http://nexus.bsdn.org/content/groups/public/' }
    			maven { name "M2" ; url 'https://plugins.gradle.org/m2/' }
    		}
    	}
    }
    

    关注公众号加群,更多原创干货与你分享 ~

  • 相关阅读:
    Python eval 函数妙用
    502与504故障分析与解决方法
    [转]谈谈select, iocp, epoll,kqueue及各种网络I/O复用机制
    计算阶乘n!末尾0的个数
    C++中的Overload、Override和Overwrite
    C++中的空类与空结构体大小
    多线程编程之优先级翻转问题
    数据库原理之事务(二)
    数据库原理之事务(一)
    NoSQL之基础篇
  • 原文地址:https://www.cnblogs.com/ssgeek/p/16052709.html
Copyright © 2020-2023  润新知