关于Android Studio中,你需要知道的Gradle所有!

Gradle基础

Gradle环境配置

下载gradle解压后找到目录,例如:D:\android\gradle\gradle-4.4\bin。把地址配置到环境变量path中

Android Gradle构建生命周期

  • Initialization:初始化阶段,会执行项目根目录下的settings.gradle文件,来分析哪些项目参与构建
  • Configuration:配置阶段,配置阶段会去加载所有参与构建的项目的build.gradle文件,
    会将每build.gradle文件实例化为一个Gradle的project对象
  • Execution:执行阶段,开始打包

Gradle Wrapper

  • Gradle的一层包装,便于开发中统一构建版本。当启动Gradle时,Wrapper会检查Gradle有没有被下载关联。 在 Wrapper中包含gradle-wrapper.jar和gradle-wrapper.properties。
  • gradlew和gradlew.bat分别是Linux和Windows下的可执行脚本。Gradle-wrapper.jar是具体业务逻辑包,gradlwe最终还是使用Java执行的这个jar。
  • gradle-wrapper.properties中的配置:distributionBase 下载的gradle压缩包解压后存储主路径;distributionPath 相对于distributionBase的解压后的gradle压缩包的路径; zipStoreBase 同distributionBase ,只不过是存放zip压缩包的; zipStorePath 同distributionPath ,只不过是存放zip压缩包的; distributionUrl Gradle发行版本压缩包的下载地址。

Groovy基础

Groovy是基于JVM虚拟机的一种动态语言, 它的语法和Java非常相似,是一种灵活的动态脚本语言。每个Gradle的build脚本都是一个Groovy脚本。Groovy是弱类型语言,语法更加灵活,不用像Java中的类以及数据类型需要强制转换,如下示例:

字符和字符串

task hello << {
      def name='a‘
      println '单引号:${name}‘
      println "双引号:${name}"
	  }
//输出结果
单引号:${name}
双引号:a

     
     
  • 不管是单引号还是双引号都是String类型。
  • 单引号没有运算能力。
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    集合,List集合,Map集合

    //List集合
    task printList << {
          def numList=[1,2,3,4,5,6]
          println numList[1]//访问第二个元
          println numList[-1]//访问最后一个元素
          println numList[-2]//访问倒数第二个元素
          println numList[1..3]//访问第二个到第四个元素
    }
    //Map集合
    task printMap << {
          def map=["width":1080,"height":800]
          println map["width"]//访问第二个元素
          map.each{
                 println "Key:${it.key},Value:${it.value}"
          }
    }
    
         
         
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    闭包

    闭包在很多语言中都有这种概念,在Java8中Lambda表达式也是闭包的形式。另外在javascript,kotlin中都有闭包的概念。如下示例:

    定义方法customEach,它只有一个参数用于接收闭包代码块。如果只有一个参数,就用it代替。

    task printClosure << {
          //使用我们自定义的闭包
          customEach{
                 println it
          }
    }
     //自定义方法
    def customEach(closure){
         for(int i in 1..10){
                 closure(i)
         }
    }
    
         
         
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    定义方法eachMap,为闭包传递两个参数,key ,value,多个参数就不能用it了,必须要显示声明出来。

    task printClosure << {
          //使用我们自定义的闭包
          eachMap{k , v ->
                     println "${k} is ${v}"
          }
    }
    //自定义方法
    def eachMap(closure){
          def map=["name":"张三","age":18]
          map.each{
                 closure(it.key,it.value)
          }
    }
    
         
         
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    自定义属性

    //自定义 工具版本号
    ext.build_tools_version = "25.0.2"
    

    //引用版本号
    buildToolsVersion build_tools_version

    • 1
    • 2
    • 3
    • 4
    • 5

    脚本即代码,代码也是脚本

    这段代码是生成时间,可以用于打包文件名

    def buildTime(){
        def date=new Date()
        def formattedDate=date.format('yyyyMMdd')
        return formattedDate
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5

    Gradle插件

    二进制插件

    apply plugin:'java’
    
      
      
    • 1

    二进制插件就是实现了org.gradle.api.Plugin接口,需要有plugin id。

    应用脚本插件

    apply from:'version.gradle’ 
    
      
      
    • 1

    应用脚本插件就是执行了version.gradle一段脚本代码。

    第三方插件

    apply plugin:'com.android.application’ 
    

    classpath ‘com.android.tools.build:gradle:1.5.0’

    • 1
    • 2
    • 3

    第三方发布的作为jar的二进制插件。

    Android Gradle配置

    默认配置

     compileSdkVersion 28
     buildToolsVersion '25.0.1'
     defaultConfig {
            applicationId "com.sort.demo"
            minSdkVersion 15
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
     }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • applicationld:用于指定生成app的包名。
    • minSdkVersion:最低支持的sdk版本。
    • targetSdkVersion:用于配置基于哪个Android Sdk开发。
    • compileSdkVersion:当前app编译版本。
    • versionCode:用于配置App内部版本号,通常用于版本升级。
    • versionName:用于配置App的版本名称,是让用户知道当前的版本。
    • resConfigs:过滤语言

    signingConfigs 签名信息配置

    signingConfigs{
            debug{
                storeFile file("debug.keystore")
                storePassword "password"
                keyAlias "test"
                keyPassword "password"
            }
            release{
                storeFile file(“release.keystore”) //签名证书文件
                storePassword “password” //签名证书文件密码
                keyAlias “test” //签名证书秘钥别名
                keyPassword “password” //签名证书秘钥密码
            }
     }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    signingConfigs 需要写在defaultConfig 和buildTypes 前面,不然会编译报错。默认情况下debug模式签名已经配置好了,在$HOME/.android/debug.keystore。

    buildTypes 构建类型

    buildTypes {
            debug {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                signingConfig signingConfigs.debug
            }
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                signingConfig signingConfigs.release
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    buildTypes的属性:

    • applicationIdSuffix:应用id后缀
    • versionNameSuffix:版本名称后缀
    • minifyEnabled:是否混淆
    • proguardFiles:混淆文件
    • singningConfig:签名配置
    • manifestPlaceholders:清单占位符
    • shrinkResources:是否去除未使用的资源
    • zipAlignEnable:是否使用zipalign工具压缩
    • multiDexEnabled:是否拆分成多个Dex
    • multiDexKeepFile:指定文本文件编译进主Dex文件中
    • multiDexKeepProguard:指定混淆文件编译进主Dex文件中

    sourceSets

    每一个BuildType都会生成一个SourceSet,默认位置为src//。一个SourceSet包含源代码,资源文件等信息。针对不同的BuildType,可以单独为其指定Java源代码,res资源等。jniLibs目录下放置的是so库文件,直接放在目录下即可。如果so是在libs中,那就需要单独配置了,如下jniLibs.srcDirs=[‘libs’]。

     sourceSets {
                main {
                    res.srcDirs =
                            [
                                    'src/main/res/google',
                                    'src/main/res/baidu'
                            ]
                    jniLibs.srcDirs = ['libs']
                }
     }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    开发中我们会引用到aar这样的架包, 如果aar中的libs存在架包,也需要单独配置,配置如下:

    repositories {
        flatDir {
            dirs 'libs'
        }
     }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5

    使用abiFilters 过滤,其实这个可以不设置,这样编译时,就会将项目里所有依赖资源包里的so库都打到最终的apk里。但是有些平台,我们是不需要支持的,如果不删除的话,apk就臃肿了。如果那些so库是我们自己编译出来的,那可以直接在工程中删除对应so文件,但是如果是第三方提供的,就不好删除了,所以就需要使用abiFilters来过滤了。

    defaultConfig {
            ndk {
                abiFilters 'armeabi','armeabi-v7a','arm64-v8a'
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5

    packagingOptions

    用于解决文件冲突问题

     packagingOptions {
            exclude ’META-INF/LICENSE.txt‘
            exclude ’META-INF/LICENSE‘
     }
    
      
      
    • 1
    • 2
    • 3
    • 4

    用于解决项目中的jar冲突

    compile ('com.wdullaer:materialdatetimepicker:3.2.2') {
        exclude group: 'com.android.support', module: 'support-v4'
        exclude group: 'com.android.support', module: 'design'
    }
    
      
      
    • 1
    • 2
    • 3
    • 4

    简写方式

    compile() { dep ->
        ['support-v4', 'support-v13', 'design'].each{ module -> dep.exclude module: module }
    }
    
      
      
    • 1
    • 2
    • 3

    批量修改生成的apk文件名

    applicationVariants.all { variant ->
            variant.outputs.all { output -> // AS 3.0之后版本 each 改为 all
                def fileName = "${buildTime()}_release.apk"
                def outFile = output.outputFile
                if (outFile != null && outFile.name.endsWith('.apk')) {
                    outputFileName = fileName// AS 3.0之后版本 output.outputFile 改为 outputFileName
                }
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    动态生成版本信息

    在开发中,一个工程中有多个module,每个module都有build.gradle配置,这些配置中的版本信息可以统一管理和维护。如下示例:

    创建config.gradle内容如下

    ext {
        android = [
                compileSdkVersion: 22,
                minSdkVersion    : 19,
                targetSdkVersion : 22,
                buildToolsVersion: '25.0.0',
                versionCode      : 1,
                versionName      : "1.0.1",
        ]
        dependencies = [
                supportV4: 'com.android.support:support-v4:22.2.1',
                design   : 'com.android.support:design:22.2.0'
        ]
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在主工程中引入config.gradle

    apply from: "config.gradle"
    
      
      
    • 1

    module中引用配置的内容

     android {
        compileSdkVersion rootProject.ext.android.compileSdkVersion
        buildToolsVersion rootProject.ext.android.buildToolsVersion
        defaultConfig {
            applicationId "com.example.demo"
            minSdkVersion rootProject.ext.android.minSdkVersion
            targetSdkVersion rootProject.ext.android.targetSdkVersion
            versionCode rootProject.ext.android.versionCode
            versionName rootProject.ext.android.versionName
        }
    }
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        compile rootProject.ext.dependencies.supportV4
        compile rootProject.ext.dependencies.design
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    从git的tag中获取版本号

    git describe --abbrev=0 --tags //获取当前tag名
    
      
      
    • 1

    动态获取版本名称

     defaultConfig {
            versionCode appVersionCode
            versionName getAppVersionName()
     }
    
      
      
    • 1
    • 2
    • 3
    • 4

    从git tag中获取应用的版本名称

    def getAppVersionName() {
        def stdout = new ByteArrayOutputStream()
        exec {
            commandLine 'cmd','git', 'describe', '--abbrev=0', '--tags'
            standardOutput = stdout
        }
        return stdout.toString()
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    动态获取版本号

    defaultConfig {
            versionCode getAppVersionCode()
            versionName getAppVersionName()
    }
    
      
      
    • 1
    • 2
    • 3
    • 4

    以git tag数量作为版本号

    def getAppVersionCode(){
        def stdout=new ByteArrayOutputStream()
        exec {
            commandLine 'cmd','git','tag','--list'
            standardOutput = stdout
        }
        return split("\n").size()
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    隐藏签名文件信息

    在团队开发中如果想隐藏签名信息,把正式包的时候不受影响。把信息存到主机环境变量中,既做到隐藏也能正常打包。

    signingConfigs {
            def appStoreFile=System.getenv("STORE_FILE")
            def appStorePassword=System.getenv("STORE_PASSWORD")
            def appKeyAlias=System.getenv("KEY_ALIAS")
            def appKeyPassword=System.getenv("KEY_PASSWORD")
            //当不能从环境变量里获取到签名信息的时候,就使用项目中带debug签名
            if(!appStoreFile||!appStorePassword||!appKeyAlias||!appKeyPassword){
                appStoreFile="debug.keystore"
                appStorePassword="android"
                appKeyAlias="androiddebugkey"
                appKeyPassword="android"
            }
            release{
                storeFile (appStoreFile)
                storePassword appStorePassword
                keyAlias appKeyAlias
                keyPassword appKeyPassword
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    动态配置AndroidManifest文件

    在我们做渠道统计的时候一般会这样做,在打包的时候会把${UMENG_CHANNEL}替换成渠道名。

    <meta-data android:value="${UMENG_CHANNEL}" android:name="UMENG_CHANNEL"/>
    
      
      
    • 1

    根据渠道名来表示渠道号,这样在渠道统计的时候就能统计不同的渠道。

     productFlavors{
            google{
                manifestPlaceholders.put("UMENG_CHANNEL","google")
            }
            baidu{
                manifestPlaceholders.put("UMENG_CHANNEL","baidu")
            }
     }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    简写方式

    productFlavors {
            google { }
            baidu { }
            productFlavors.all { flavor ->
                 manifestPlaceholders.put("UMENG_CHANNEL", name)
            }    
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    自定义BuildConfig

    比如:不同的渠道想实现打开不同的网页,可以这么做。

    productFlavors {
            google {
                buildConfigField 'String','WEB_URL', ' http://www.google.com '
            }
            baidu {
                buildConfigField 'String','WEB_URL', ' http://www.baidu.com '
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    比如:测试包用测试环境,正式包用正式环境。

    buildTypes {
            debug{
                buildConfigField ' String ', ' WEB_URL ', ' http://www.ceshi.com '
            }
            release {
                buildConfigField 'String','WEB_URL', ' http://www.zhengshi.com '
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    比如:测试包开启日志,正式包关闭日志

     buildTypes {
            debug{
                buildConfigField 'bool', 'isDebug', 'true'
            }
            release {
                buildConfigField 'bool', 'isDebug', 'false'
            }
     }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    动态添加自定义的资源

    res/values中的资源,不光可以在res/values中使用xml的方式定义,还可以在gradle中定义。这样不同的渠道引用的string是不同的。还可以使用id,bool,dimen,integer,color等类型定义value资源。在BuildType中也可使用。

    productFlavors {
            google {
               resValue 'string','channel_tips','google渠道欢迎你'
            }
            baidu {
               resValue 'string','channel_tips','baidu渠道欢迎你'
            }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Java编译选项

    compileOptions {
            encoding=‘utf-8’//指定文件编码格式
            sourceCompatibility=JavaVersion.VERSION_1_8 //源代码编译级别
            targetCompatibility=JavaVersion.VERSION_1_8//生成Java字节码的版本
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5

    DEX选项配置

    在apk打包的时候被dx命令优化成Android虚拟机可执行的DEX文件。默认情况下被dx分配内存是一个G,也就是1024MB。

    dexOptions {
            javaMaxHeapSize ‘4g‘ //执行dx最大堆内存
            jumboMode true  //忽略方法数限制的检查,apk无法再低版本的设备上面安装
            threadCount 2    //dx使用的线程数
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5

    lintOptions

    程序在编译的时候会检查lint,有任何错误提示会停止build,我们可以关闭这个开关。

    lintOptions {
            abortOnError false //即使报错也不会停止打包
            checkReleaseBuilds false  //打包release版本的时候进行检测
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    发布了154 篇原创文章 · 获赞 89 · 访问量 10万+

    Gradle基础

    Gradle环境配置

    下载gradle解压后找到目录,例如:D:\android\gradle\gradle-4.4\bin。把地址配置到环境变量path中

    Android Gradle构建生命周期

    • Initialization:初始化阶段,会执行项目根目录下的settings.gradle文件,来分析哪些项目参与构建
    • Configuration:配置阶段,配置阶段会去加载所有参与构建的项目的build.gradle文件,
      会将每build.gradle文件实例化为一个Gradle的project对象
    • Execution:执行阶段,开始打包

    Gradle Wrapper

    • Gradle的一层包装,便于开发中统一构建版本。当启动Gradle时,Wrapper会检查Gradle有没有被下载关联。 在 Wrapper中包含gradle-wrapper.jar和gradle-wrapper.properties。
    • gradlew和gradlew.bat分别是Linux和Windows下的可执行脚本。Gradle-wrapper.jar是具体业务逻辑包,gradlwe最终还是使用Java执行的这个jar。
    • gradle-wrapper.properties中的配置:distributionBase 下载的gradle压缩包解压后存储主路径;distributionPath 相对于distributionBase的解压后的gradle压缩包的路径; zipStoreBase 同distributionBase ,只不过是存放zip压缩包的; zipStorePath 同distributionPath ,只不过是存放zip压缩包的; distributionUrl Gradle发行版本压缩包的下载地址。

    Groovy基础

    Groovy是基于JVM虚拟机的一种动态语言, 它的语法和Java非常相似,是一种灵活的动态脚本语言。每个Gradle的build脚本都是一个Groovy脚本。Groovy是弱类型语言,语法更加灵活,不用像Java中的类以及数据类型需要强制转换,如下示例:

    字符和字符串

    task hello << {
          def name='a‘
          println '单引号:${name}‘
          println "双引号:${name}"
    	  }
    //输出结果
    单引号:${name}
    双引号:a
    
      
      
  • 不管是单引号还是双引号都是String类型。
  • 单引号没有运算能力。
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    集合,List集合,Map集合

    //List集合
    task printList << {
          def numList=[1,2,3,4,5,6]
          println numList[1]//访问第二个元
          println numList[-1]//访问最后一个元素
          println numList[-2]//访问倒数第二个元素
          println numList[1..3]//访问第二个到第四个元素
    }
    //Map集合
    task printMap << {
          def map=["width":1080,"height":800]
          println map["width"]//访问第二个元素
          map.each{
                 println "Key:${it.key},Value:${it.value}"
          }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    闭包

    闭包在很多语言中都有这种概念,在Java8中Lambda表达式也是闭包的形式。另外在javascript,kotlin中都有闭包的概念。如下示例:

    定义方法customEach,它只有一个参数用于接收闭包代码块。如果只有一个参数,就用it代替。

    task printClosure << {
          //使用我们自定义的闭包
          customEach{
                 println it
          }
    }
     //自定义方法
    def customEach(closure){
         for(int i in 1..10){
                 closure(i)
         }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    定义方法eachMap,为闭包传递两个参数,key ,value,多个参数就不能用it了,必须要显示声明出来。

    task printClosure << {
          //使用我们自定义的闭包
          eachMap{k , v ->
                     println "${k} is ${v}"
          }
    }
    //自定义方法
    def eachMap(closure){
          def map=["name":"张三","age":18]
          map.each{
                 closure(it.key,it.value)
          }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    自定义属性

    //自定义 工具版本号
    ext.build_tools_version = "25.0.2"
    

    猜你喜欢

    转载自blog.csdn.net/qq_41933149/article/details/103749973
    今日推荐