Gradle

  浅谈构建工具

Posted by MrCodeSniper on February 22, 2017

前言

AndroidStudio中第一使用的工程构建工具,明白这个能便捷我们之后的开发

Gradle是什么

Gradle是一个基于Groovy语言的强大的构建系统,Groovy则是在Java基础上扩展的、运行在JVM上的一种脚本语言。

通过丰富的插件扩展,Gradle可以支持Java、JavaWeb、Groovy、Android等工程的编译,同时可以很方便的从Maven、Ant等迁移过来。

执行Gradle任务的过程,主要就是在运行Java/Groovy代码。编译期间如果有代码抛出了异常,就会中断编译过程。

在Android Studio中开发时,编译就是基于Gradle实现的。Android Studio中内置了Gradle。

成员介绍

Gradle Wrapper

用IDEA/Android Studio创建基于Gradle的工程时,默认会在工程根目录创建GradleWrapper

包括gradlew可执行文件和gradlew.bat批处理文件 和gradle/wrapper文件夹 其中包含gradle-wrapper.jar和gradle-wrapper.properties文件

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists //调用路径
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists  //存储路径
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip //下载地址

Project、RootProject、SubProject (Module)

Project是Gradle中的基本概念之一,即一个工程。一个工程可以包含多个SubProject,也称为Module,最顶层的工程也称为RootProject。

android工程结构

每个build.gradle对应一个Project 外层的是RootProject,里面的app是SubProject。

settings.gradle 当导入app库时会添加依赖 通常新创建的app工程只有一个主模块 include ‘:app’

结构

settings.gradle
build.gradle
app
    build.gradle

gradle.properties

Properties文件格式可由java.util.Properties解析,包含若干键值对,类似HashMap<String,String>。

旧版本使用ndk时 需添加这样一条配置 android.useDeprecatedNdk=true

一些key还可以作为变量使用

//在gradle.properties设置的k,v
SUPPORT_LIBRARY_VERSION=23.4.0
//在build.gradle使用
dependencies {
    compile "com.android.support:support-v4:${SUPPORT_LIBRARY_VERSION}"
    compile "com.android.support:appcompat-v7:${SUPPORT_LIBRARY_VERSION}"
    compile "com.android.support:design:${SUPPORT_LIBRARY_VERSION}"
    compile "com.android.support:recyclerview-v7:${SUPPORT_LIBRARY_VERSION}"
}

Gradle编译

编译就是将程序源码转换成可执行文件或中间代码的过程。具体到android,就是将.java代码文件变成.class进一步转为.dex字节码的过程

Gradle基于Groovy,Groovy是在Java基础上扩展的脚本语言。Groovy有和解释型语言一样的特性,可以直接从源码运行而不需要提前编译。但实际运行过程中,也是先转换成Java的class文件,再运行在JVM上的。

在buildscript的dependencies中,通过classpath语句引用一些编译好的jar包,Gradle在执行时就会将其下载并加入Java的classpath,其中的class在编译时就可以被调用,运行在电脑或云主机上。

Gradle Android Plugin

buildscript {
    dependencies {
        // 引入了Gradle Android插件
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
}
//应用插件
// 对于Android Application(APK)
apply plugin: 'com.android.application'

// 对于Android Library(AAR)
apply plugin: 'com.android.library'
//应用插件定义的dsl
android {
    compileSdkVersion 24
    buildToolsVersion '25.0.2'

    defaultConfig {
        applicationId "com.paincker.lint.demo"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }
}

Repositories

Gradle的依赖管理完全兼容Maven和Ivy,常使用Maven仓库来实现依赖管理,当Library打包完成后上传到Maven仓库,Gradle则会从Maven仓库下载需要的依赖。

Repository就是用来指定所需要的Maven仓库。除了常见的jcenter(),mavenCentral(),还可以指定本地搭建的Maven仓库、指定URL的Maven仓库等

repositories {
    jcenter()
    mavenCentral()
    maven { url 'http://maven.oschina.net/content/groups/public/' }
    ivy { url "http://repo.mycompany.com/repo" }
    localRepository { dirs 'lib' }
    maven {
        url "sftp://repo.mycompany.com:22/maven2"
        credentials {
            username 'user'
            password 'password'
        }
    }
}

Dependencies

依赖管理

compile "org.gradle.test.classifiers:service:1.0:jdk15@jar"//外部依赖
compile project(':someProject')//工程依赖
compile files('hibernate.jar', 'libs/spring.jar')
compile fileTree('libs')//文件依赖

ProductFlavor、BuildType与Build Variant

这个配置能实现 我们发布项目到不同渠道的打包

// 渠道配置
productFlavors {
            wandoujia {}
            _360 {}
            baidu {}
            xiaomi {}
}
productFlavors.all { flavor ->flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] //动态地修改AndroidManifest中的渠道名}
//签名配置
        signingConfigs {
            debug {
                // No debug config
                storeFile file("${rootDir}/keystores/xqsg_debug.jks") //debug证书
            }
            release {
                storeFile file("${rootDir}/keystores/xqsg.jks") //release证书
                storePassword "test"                            //签名证书密码
                keyAlias "test"                                 //别名
                keyPassword "test"                              //别名密码
            }
        }
    //编译类型
    buildTypes {
            debug {//测试
                buildConfigField("boolean", "LOG_ON", "true")//通过编译类型配置日志开关
                versionNameSuffix "-debug"                       //包名后缀为“-debug”
                minifyEnabled false                              //是否混淆
                zipAlignEnabled false                            //Zipalign优化
                shrinkResources false                            // 移除无用的resource文件
                signingConfig signingConfigs.debug               //使用debug证书签名
            }
            release {//发布
                buildConfigField "boolean", "LOG_ON", "false" //不显示Log
                minifyEnabled true                               //开启混淆
                zipAlignEnabled true                             //开启Zipalign优化
                shrinkResources true                             //移除无用的resource文件,此项只有在开启混淆时才生效
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                signingConfig signingConfigs.release             //使用release证书签名
                //多渠道打包配置
                applicationVariants.all { variant ->
                    variant.outputs.each { output ->
                        def outputFile = output.outputFile
                        if (outputFile != null && outputFile.name.endsWith('.apk')) {
                            // 输出apk名称为test_v1.0_2016-08-15_wandoujia.apk
                            def fileName = "test_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                            output.outputFile = new File(outputFile.parent, fileName)
                        }
                    }
                }
            }
        }

更新日志

高版本gradle依赖指令

compile与api完全相同

implementation指令

这个指令的特点就是,对于使用了该命令编译的依赖,对该项目有依赖的项目将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开。

总结:依赖不会传递

当module a implementation ‘com.google.code.gson:gson:2.8.2’ 则这个模块可以使用gson

当module b 依赖了模块a implementation project(‘:a’)

module b用不了gson 若用api来代理implemention则可以使用

provided指令

只提供编译支持,但是不会写入apk。比如我在编译的时候对某一个jar文件有依赖,但是最终打包apk文件时,我不想把这个jar文件放进去,可以用这个命令。

Provided是间接的得到了依赖的Library,运行的时候必须要保证这个Library的存在,否则就会崩溃,起到了避免依赖重复资源的作用。

annotationProcessor指令

了解这个指令之前必须了解 apt的概念

APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码 (编译时)

APT自动执行 1.扫描代码中的注解 2.根据注解定义的处理方式进行操作 3.编译生成java文件

annotationProcessor是APT工具中的一种,他是google开发的内置框架,不需要引入,可以直接在build.gradle文件中使用,如下

dependencies {
     annotationProcessor project(':xx')
     annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}

参考