与Gradle的那些年

既然要学习Gradle,首先要知道它是什么,它又能干什么,以及怎么使用它。

Gradle是什么?

Gradle 是以Groovy为基础,面向java应用,基于DSL语法的自动化构建工具。
是google引入,替换ant和maven的新工具,其依赖兼容maven和ivy。

Gradle能干什么?

1.更容易重用资源和代码;
2.可以更容易创建不同的版本的程序,多个类型的apk包;
3.更容易配置,扩展;
4.更好的IDE集成;

Android Studio中的android项目通常至少包含两个build.gradle文件,一个是project范围的,另一个是module范围的,由于一个project可以有多个module,所以每个module下都会对应一个build.gradle。

project->build.gradle

project下的build.gradle是整个project的配置,主要配置gradle 版本及 全局依赖仓库、库或者其他全部参数。android studio 现在重要仓库采用jcenter(),之前版本放在mavenCentral。另外有时还没有加入jcenter()仓库的第三方库,也需要在这里配置他们的库地址。需要在这里配置,才能将第三方库拉下来。

apply from: "config.gradle"
buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
        jcenter()
        maven {
            url 'https://jitpack.io'
        }
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.sensorsdata.analytics.android:android-gradle-plugin2:1.0.2'
        classpath "io.realm:realm-gradle-plugin:4.1.1"
    }
}
allprojects {
    repositories {
        mavenLocal()
        mavenCentral()
        jcenter()
        maven {
            url 'https://jitpack.io'
        }
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }
    }
}

apply from: "config.gradle" :外部配置文件,下面会讲到
buildscript和allprojects中都包含有repositories,是因为他们的作用域不同,buildscript中的仓库是gradle脚本自身需要的资源,而allprojects下的仓库是项目所有模块需要的资源。

config.gradle

ext {

    android = [
            //编译SDK的版本
            compileSdkVersion: 26,
            //buildtool 的版本
            buildToolsVersion: "26.0.2",
            //支持最小android sdk 版本
            minSdkVersion    : 17,
            // 目标版本
            targetSdkVersion : 26
            //应用版本号
            versionCode = 1
            //应用版本名称
            versionName = "v1.0.0"
    ]

    dependVersion = [
            support: "26.0.2"
    ]
    //服务器一 路由地址
    serverOneAPIUrl = [
            api_url_debug  : "\"https://devone.gradle.cn/\"",//开发
            api_url_test   : "\"https://testone.gradle.cn/\"",//内测 
            api_url_preview: "\"https://preone.gradle.cn/\"",//预览
            api_url_release: "\"https://one.gradle.cn/\""//正式
    ]
   //服务器二 路由地址
   serverTwoAPIUrl = [
            api_chat_url_debug  : "\"https://devtwo.gradle.cn/\"",//开发
            api_chat_url_test   : "\"https://testtwo.gradle.cn/\"",//内测
            api_chat_url_preview: "\"https://pretwo.gradle.cn/\"",//预览
            api_chat_url_release: "\"https://two.gradle.cn/\""//正式
    ]
    //服务器三 路由地址
    serverThreeUrl = [
            api_url_debug  : "\"https://devthree.gradle.cn/\"",//开发
            api_url_test   : "\"https://testthree.gradle.cn/\"",//内测
            api_url_preview: "\"https://prethree.gradle.cn/\"",//预览
            api_url_release: "\"https://three.gradle.cn/\""//正式
    ]

    dependencies = [
            //------------- 分包  ------------
            multidex                  : "com.android.support:multidex:1.0.1",

            // ------------- Android -------------
            supportV4                 : "com.android.support:support-v4:${dependVersion.support}",
            appcompatV7               : "com.android.support:appcompat-v7:${dependVersion.support}",
            design                    : "com.android.support:design:${dependVersion.support}",
            cardview                  : "com.android.support:cardview-v7:${dependVersion.support}",
            junit                     : "junit:junit:4.12",

            // ------------- reyclerview ------------
            recyclerview              : "com.android.support:recyclerview-v7:${dependVersion.support}",

            // ------------- 网络请求 -------------
            retrofit                  : 'com.squareup.retrofit2:retrofit:2.3.0',
            retrofit_rxjava           : 'com.squareup.retrofit2:adapter-rxjava2:2.3.0',
            retrofit_converter_gson   : 'com.squareup.retrofit2:converter-gson:2.3.0',
            okhttp_logging_interceptor: 'com.squareup.okhttp3:logging-interceptor:3.8.0',

            // ------------- 图片加载 -------------
            glide                     : 'com.github.bumptech.glide:glide:4.3.1',
            glideAp                     : 'com.github.bumptech.glide:compiler:4.3.1',

            // ------------- 通信 -------------
            eventbus                  : 'org.greenrobot:eventbus:3.0.0',

            // ------------- RxAndroid -------------
            rxAndroid                 : 'io.reactivex.rxjava2:rxandroid:2.0.1',
            rxJava                    : 'io.reactivex.rxjava2:rxjava:2.0.1',

            // ------------- json解析 -------------
            gson                      : 'com.google.code.gson:gson:2.8.1',
    ]
}

项目配置文件,ext全局变量,在每个module的build.gradle文件中都可以随时引用

module->build.gradle

apply plugin: 'com.android.application'
android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion

    //加载本地配置文件local.properties
    Properties properties = new Properties()
    InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream();
    properties.load(inputStream)

    //安卓构建过程需要配置的参数
    defaultConfig {
        applicationId "com.demo.gradle"
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        multiDexEnabled true
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
    }
    //ndk配置参数
    ndk {
        abiFilters "armeabi-v7a", "arm64-v8a", "x86"
    }
    //java版本号
    compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
    }
    //渠道Flavors_打包
    productFlavors {
        //可以设置不同渠道渠道号,应用名称
        dev { // 开发
            buildConfigField "String", "CHANNEL_NUMBER", '"11111"'
        }
        '360' {
            buildConfigField "String", "CHANNEL_NUMBER", '"11112"'
        }
        GooglePlay {
            buildConfigField "String", "CHANNEL_NUMBER", "11113"'
    }

    //定义apk文件名称格式
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}_${releaseFormatTime()}.apk")
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }
    }

    //签名
    signingConfigs {
        release {
            keyAlias properties.getProperty('keyAlias')
            keyPassword properties.getProperty('keyPassword')
            storeFile file(properties.getProperty('storeFile'))
            storePassword properties.getProperty('storePassword')
        }
    }

    buildTypes {
        debug {
            minifyEnabled false
            zipAlignEnabled false
            shrinkResources false
            (..各个服务器的dubug路由地址..)
        }

         preview {
            debuggable false // 是否保留调试信息
            minifyEnabled true  //是否混淆
            zipAlignEnabled true // 包优化
            shrinkResources true // 移除不必要的资源
            // 签名
            signingConfig signingConfigs.release
            // 代码混淆规则文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            (..各个服务器的preview路由地址..)
        }

        release {
            //加上后缀
            applicationIdSuffix ".release"
            minifyEnabled true //是否混淆
            zipAlignEnabled true // zip对齐优化
            shrinkResources true // 移除不必要的资源

            // 不显示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"

            // 签名
            signingConfig signingConfigs.release
            //混淆文件的位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            (..各个服务器的release路由地址..)
        }
    }

    // 为了解决部分第三方库重复打包了META-INF的问题
    packagingOptions {
        exclude 'META-INF/ASL2.0'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/MANIFEST.MF'
        exclude 'sign.properties'
        exclude 'keystore.jks'
    }

    //执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。
    lintOptions {
        abortOnError false
    }
   
    dataBinding {
        enabled = true
    }

    dexOptions {
        //支持最大工程模式
        jumboMode = true 
        javaMaxHeapSize "10g"
        //使用增量模式
        //incremental false

        preDexLibraries = false //预编译
        threadCount = "8" //线程数目
    }

}
//定义打包时间格式化
def releaseFormatTime() {
    return new Date().format("yyyy-MM-dd HH:mm", TimeZone.getDefault())
}

// 发布的日更新包时间尾巴
def releaseFormatDayTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getDefault())
}
// 定义打包时间戳
def releaseTime() {
    return new Date().getTime();
}

repositories {
    flatDir {
        dirs 'aars'
    }
    maven {
        url 'https://maven.google.com/'
        name 'Google'
    }
}
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile rootProject.ext.dependencies.multidex
    compile rootProject.ext.dependencies.bugtags
    //------------  Android support  -----------
    //compile rootProject.ext.dependencies.supportV4
    compile rootProject.ext.dependencies.design
    compile rootProject.ext.dependencies.appcompatV7
    compile rootProject.ext.dependencies.cardview
    //------------  recyclerview  -------------
    compile rootProject.ext.dependencies.recyclerview
    compile rootProject.ext.dependencies.recyclerview_divider
    //------------  通信  --------------
    compile rootProject.ext.dependencies.eventbus
    //------------  网络  ----------
    compile project(':api')
    //------------  rxAndroid-----------
    compile rootProject.ext.dependencies.rxAndroid
    compile rootProject.ext.dependencies.topsnackbar
    compile rootProject.ext.dependencies.glide
    annotationProcessor rootProject.ext.dependencies.glideAp
}

1.buildTypes是指建构的类型,一般只用两种默认类型 debug 和 release,顾名思义 debug 用来配置开发过程中的一些内容;release 用来配置正式发布版本的内容。有时我们需要发布介于debug与release之间的preview 版本。
2.签名信息,可以直接将信息写到gradle.properties或者,然后在然后在build.gradle中引用即可。
3.多渠道的关键在于定义不同的product flavor。这里的flavor名如果是数字开头,必须用引号引起来。

BuildConfig

在build.gradle中配置buildConfigField参数,编译后会在..\app\build\generated\source\buildConfig文件夹下会自动生成对应版本对应module的BuildConfig.java。BuildConfig就会包含对应版本的配置信息。程序中可以直接引用这些数据。例如BuildConfig.DEBUG。

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.demo.gradle";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "wandoujia";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "v1.0.0_debug";
  public static final int BUILD_TYPE_INT = 0;
  public static final boolean IS_DEBUG = true;
  (..各个服务器路由地址..)
}

module 调整目录结构sourceSets

默认情况下,java文件和resource文件分别在src/main/java和src/main/res目录下,在build.gradle文件,andorid{}里面添加下面的代码,便可以将java文件和resource文件放到src/java和src/resources目录下。

sourceSets {
   min.java.srcDirs = ['src/java']
   min.resources.srcDirs = ['src/resources']
}

Gradle常用命令

./gradlew, ./代表当前目录,gradlew代表 gradle wrapper,意思是gradle的一层包装,大家可以理解为在这个项目本地就封装了gradle,即gradle wrapper, myAPP/gradle/wrapper/gralde-wrapper.properties**文件中声明了它指向的目录和版本。只要下载成功即可用grdlew wrapper的命令代替全局的gradle命令。

理解了gradle wrapper的概念,下面一些常用命令也就容易理解了。

./gradlew 下载更新gradle
./gradlew -v 版本号
./gradlew assemble 构建项目输出
./gradlew check 运行检测和测试任务
./gradlew clean 清除9GAG/app目录下的build文件夹
./gradlew build 运行check和assemble,检查依赖并编译打包
这里注意的是 ./gradlew build 命令把debug、release环境的包都打出来,如果正式发布只需要打Release的包,该怎么办呢,下面介绍一个很有用的命令 assemble<build type="" name="">, 如</build>
./gradlew assembleDebug 编译并打Debug包
./gradlew assembleRelease 编译并打Release的包所有渠道的
./gradlew assembleWandoujiaRelease 编译并打包豌豆荚的Release版本
./gradlew assembleWandoujia 编译并打包豌豆荚的所有版本
./gradlew installRelease Release模式打包并安装
./gradlew uninstallRelease 卸载Release模式包

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容