Gradle配置最佳實(shí)踐

Gradle配置最佳實(shí)踐

本文會(huì)不定期更新凭需,推薦watch下項(xiàng)目。如果喜歡請(qǐng)star肝匆,如果覺得有紕漏請(qǐng)?zhí)峤籭ssue粒蜈,如果你有更好的點(diǎn)子可以提交pull request。本文意在分享作者在實(shí)踐中掌握的關(guān)于gradle的一些技巧旗国。

本文固定連接:https://github.com/tianzhijiexian/Android-Best-Practices

本文有部分關(guān)于加速配置的內(nèi)容在Android打包提速實(shí)踐已經(jīng)有所涉及枯怖,如果有想了解打包加速的內(nèi)容,可以移步去閱讀能曾。

需求

隨著android的發(fā)展度硝,新技術(shù)和新概念層出不窮。不同的測(cè)試環(huán)境寿冕、不同的分發(fā)渠道蕊程、不同的依賴方式,再加上各大廠家“優(yōu)秀”的插件化方案驼唱,這些給我們的開發(fā)工作帶來了新的需求藻茂。我希望可以通過gradle這個(gè)令人又愛又恨的東西來解決這些問題。

實(shí)現(xiàn)

調(diào)整gradle的編譯參數(shù)

gradle.properties中允許我們進(jìn)行各種配置:

配置大內(nèi)存:

org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

守護(hù)進(jìn)程

org.gradle.daemon=true

并行編譯

org.gradle.parallel=true

開啟緩存:

android.enableBuildCache=true

開啟孵化模式:

org.gradle.configureondemand=true

以上的配置需要針對(duì)自身進(jìn)行選擇曙蒸,隨意配置大內(nèi)存可能會(huì)出現(xiàn)oom捌治。如果想了解這樣配置的原理,請(qǐng)移步官方文檔纽窟。

寫死庫的版本

dependencies {? ? compile'com.google.code.gson:gson:2.+'// 不推薦的寫法}

這樣的寫法可以保證庫每次都是最新的肖油,但也帶來了不少的問題

每次build時(shí)會(huì)向網(wǎng)絡(luò)進(jìn)行檢查,國內(nèi)訪問倉庫速度很慢

庫更新后可能會(huì)更改庫的內(nèi)部邏輯和帶來bug臂港,這樣就無法通過git的diff來規(guī)避此問題

每個(gè)開發(fā)者可能會(huì)得到不同的最新版本森枪,帶來潛在的隱患

推薦寫成固定的庫版本:

dependencies {? ? compile'com.google.code.gson:gson:2.2.1'}

即使是jar包和aar视搏,我也期望可以寫一個(gè)固定的版本號(hào),這樣每次升級(jí)就可以通過git找到歷史記錄了县袱,而不是簡單的看jar包的hash是否變了浑娜。

全局設(shè)定編碼

allprojects {? ? repositories {? ? ? ? jcenter()? ? }? ? tasks.withType(JavaCompile){? ? ? ? options.encoding ="UTF-8"}}

支持groovy

在根目錄的build.gradle中:

apply plugin:'groovy'allprojects {// ...}dependencies {? ? compile localGroovy()}

設(shè)置java版本

如果是在某個(gè)module中設(shè)置,那么就在其build.gradle中配置:

android {

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_7

targetCompatibility JavaVersion.VERSION_1_7

}

}

如果想要做全局配置式散,那么就在根目錄的build.gradle中配置:

allprojects {

repositories {

jcenter()

}

tasks.withType(JavaCompile) {

sourceCompatibility = JavaVersion.VERSION_1_7

targetCompatibility = JavaVersion.VERSION_1_7

}

}

當(dāng)我們?cè)谑褂?a target="_blank" rel="nofollow">Gradle Retrolambda Plugin的時(shí)候筋遭,就會(huì)用到上述的配置(未來遷jack的時(shí)候也或許會(huì)用到)。

將密碼等文件統(tǒng)一配置

密碼和簽名這類的敏感信息可以統(tǒng)一進(jìn)行存放暴拄,不進(jìn)行硬編碼漓滔。在gradle.properies中,我們可以隨意的定義key-value乖篷。

格式:

key value

例子:

STORE_FILE_PATH ../test_key.jks

STORE_PASSWORD test123

KEY_ALIAS kale

KEY_PASSWORD test123

PACKAGE_NAME_SUFFIX .test

TENCENT_AUTHID tencent123456

配置后响驴,你就可以在build.gradle中隨意使用了。

signingConfigs {

release {

storeFile file(STORE_FILE_PATH)

storePassword STORE_PASSWORD

keyAlias KEY_ALIAS

keyPassword KEY_PASSWORD

}

}

上述僅僅是應(yīng)對(duì)于密碼等信息的存放撕蔼,其實(shí)你可以將這種方式用于插件化(組件化)等場景豁鲤。

設(shè)置本地項(xiàng)目依賴

facebook的react native因?yàn)楦滤俣群芸欤琷center的倉庫已經(jīng)無法達(dá)到實(shí)時(shí)的程度了(估計(jì)是官方懶得提交)鲸沮,所以我們需要做本地的庫依賴琳骡。

先將庫文件放入一個(gè)目錄中:

接著配置maven的url為本地地址:

allprojects {? ? repositories {? ? ? ? maven {// All of React Native (JS, Obj-C sources, Android binaries) is installed from npmurl"$rootDir/module_name/libs/android"}? ? }}

路徑都是可以隨意指定的,關(guān)鍵在于$rootDir這個(gè)參數(shù)讼溺。

設(shè)置第三方maven倉庫

maven倉庫的配置很簡單日熬,關(guān)鍵在于url這個(gè)參數(shù),下面是一個(gè)例子:

allprojects {? ? repositories {? ? ? ? maven {? ? ? ? ? ? url'http://repo.xxxx.net/nexus/'name'maven name'credentials {? ? ? ? ? ? ? ? username ='username'password ='password'}? ? ? ? }? ? }}

其中name和credentials是可選項(xiàng)肾胯,視具體情況而定。如果你用jitpack的庫的話就需要用到上面的知識(shí)點(diǎn)了耘纱。

allprojects {? ? repositories {? ? ? ? jcenter()? ? ? ? maven {? ? ? ? ? ? url"https://jitpack.io"}? ? }}

刪除unaligned apk

每次打包后都會(huì)有unaligned的apk文件敬肚,這個(gè)文件對(duì)開發(fā)來說沒什么意義,所以可以配置一個(gè)task來刪除它束析。

dependencies {? ? compile fileTree(include: ['*.jar'],dir:'libs')// ...}android.applicationVariants.all { variant ->? ? variant.outputs.each { output ->// 刪除unaligned apkif(output.zipAlign !=null) {? ? ? ? ? ? output.zipAlign.doLast {? ? ? ? ? ? ? ? output.zipAlign.inputFile.delete()? ? ? ? ? ? }? ? ? ? }? ? }}

更改生成文件的位置

如果你希望你庫生成的aar文件都放在特定的目錄艳馒,你可以采用下列配置:

android.libraryVariants.all { variant ->? ? variant.outputs.each { output ->if(output.outputFile !=null&& output.outputFile.name.endsWith('.aar')) {? ? ? ? ? ? def name ="${rootDir}/demo/libs/library.aar"output.outputFile = file(name)? ? ? ? }? ? }}

apk等文件也可以進(jìn)行類似的處理(這里再次出現(xiàn)了${rootDir}關(guān)鍵字)。

lint選項(xiàng)開關(guān)

lint默認(rèn)會(huì)做嚴(yán)格檢查员寇,遇到包錯(cuò)誤會(huì)終止構(gòu)建過程弄慰。你可以用如下開關(guān)關(guān)掉這個(gè)選項(xiàng),不過最好是重視下lint的輸出蝶锋,有問題及時(shí)修復(fù)掉陆爽。

android {? ? lintOptions {? ? ? ? disable'InvalidPackage'checkReleaseBuildsfalse// Or, if you prefer, you can continue to check for errors in release builds,// but continue the build even when errors are found:abortOnErrorfalse}}

引用本地aar

有時(shí)候我們有部分代碼需要多個(gè)app共用,在不方便上傳倉庫的時(shí)候扳缕,可以做一個(gè)本地的aar依賴慌闭。

把a(bǔ)ar文件放在某目錄內(nèi)别威,比如就放在某個(gè)module的libs目錄內(nèi)

在這個(gè)module的build.gradle文件中添加:

repositories { flatDir {? ? dirs'libs'//this way we can find the .aar file in libs folder}}

之后在其他項(xiàng)目中添加下面的代碼后就引用了該aar

dependencies { compile(name:'aar的名字(不用加后綴)',ext:'aar')}

如果你希望把a(bǔ)ar放在項(xiàng)目的根目錄中,也可以參考上面的配置方案驴剔。在根目錄的build.gradle中寫上:

allprojects {? repositories {? ? ? jcenter()? ? ? flatDir {? ? ? ? dirs'libs'}? }}

依賴項(xiàng)目中的module和jar

工程可以依賴自身的module和jar文件省古,依賴方式如下:

dependencies {? ? compile project(':mylibraryModule')? ? compile files('libs/sdk-1.1.jar')}

這種的寫法十分常用,語法格式不太好記丧失,但一定要掌握豺妓。

根據(jù)buildType設(shè)置包名

android {? ? defaultConfig {? ? ? ? applicationId"com"http:// 這里設(shè)置了com作為默認(rèn)包名}? ? buildTypes {? ? ? ? release {? ? ? ? ? ? applicationIdSuffix'.kale.gradle'// 設(shè)置release時(shí)的包名為com.kale.gradle}? ? ? ? debug{? ? ? ? ? ? applicationIdSuffix'.kale.debug'// 設(shè)置debug時(shí)的包名為com.kale.debug}? ? }

這對(duì)于flavor也是同理:

android {? ? productFlavors {? ? ? ? dev {? ? ? ? ? ? applicationIdSuffix'.kale.dev'}? ? }}

這種寫法只能改包名后綴,目前沒辦法完全更改整個(gè)包名布讹。

替換AndroidManifest中的占位符

我們?cè)趍anifest中可以有類似{appName}這樣的占位符琳拭,在module的build.gradle中可以將其進(jìn)行賦值。

android{? ? defaultConfig{? ? ? ? manifestPlaceholders = [appName:"@string/app_name"]? ? }}

flavors或buildType也是同理:

debug{? ? manifestPlaceholders = [? ? ? ? appName:"123456",? ? ]}

ShareLoginLib中就大量用到了這個(gè)技巧炒事,下面是一個(gè)例子:

[代碼地址]

我現(xiàn)在希望在build時(shí)動(dòng)態(tài)改變tencentAuthId這個(gè)的值:

[代碼地址]

release {? ? minifyEnabledfalseshrinkResourcesfalse// 是否去除無效的資源文件proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'signingConfig signingConfigs.release? ? applicationIdSuffix'.liulishuo.release'manifestPlaceholders = [// 這里的tencent123456是暫時(shí)測(cè)試用的appId"tencentAuthId":"tencent123456",? ? ]}

定義全局變量

先在project根目錄下的build.gradle定義全局變量:

ext {? ? minSdkVersion =16targetSdkVersion =24}

然后在各module的build.gradle中可以通過rootProject.ext來引用:

android {

defaultConfig {

minSdkVersion rootProject.ext.minSdkVersion

targetSdkVersion rootProject.ext.targetSdkVersion

}

}

這里添加rootProject是因?yàn)檫@個(gè)變量定義在根目錄中臀栈,如果是在當(dāng)前文件中定義的話就不用加了(詳見定義局部變量一節(jié))。

動(dòng)態(tài)設(shè)置額外信息

假如想把當(dāng)前的編譯時(shí)間挠乳、編譯的機(jī)器权薯、最新的commit版本添加到apk中,利用gradle該如何實(shí)現(xiàn)呢睡扬?此需求中有時(shí)間這樣的動(dòng)態(tài)參數(shù)盟蚣,不能通過靜態(tài)的配置文件做,動(dòng)態(tài)化方案如下:

android {? ? defaultConfig {? ? ? ? resValue"string","build_time", buildTime()? ? ? ? resValue"string","build_host", hostName()? ? ? ? resValue"string","build_revision", revision()? ? }}def buildTime() {returnnewDate().format("yyyy-MM-dd HH:mm:ss")}def hostName() {returnSystem.getProperty("user.name") +"@"+ InetAddress.localHost.hostName}def revision() {? ? def code =newByteArrayOutputStream()? ? exec {? ? ? ? commandLine'git','rev-parse','--short','HEAD'standardOutput = code? ? }returncode.toString()}

上述代碼實(shí)現(xiàn)了動(dòng)態(tài)添加了3個(gè)字符串資源:build_time卖怜、build_host屎开、build_revision, 在其他地方可像引用字符串一樣使用:

getString(R.string.build_time)// 輸出2015-11-07 17:01getString(R.string.build_host)// 輸出jay@deepin,這是我的電腦的用戶名和PC名getString(R.string.build_revision)// 輸出3dd5823, 這是最后一次commit的sha值

上面講到的是植入資源文件马靠,我們照樣可以在BuildConfig.class中增加自己的靜態(tài)變量奄抽。

defaultConfig {? ? applicationId"kale.gradle.demo"minSdkVersion14targetSdkVersion20buildConfigField("boolean","IS_KALE_TEST","true")// 定義一個(gè)bool變量resValue"string","build_time","2016.11.17"http:// 上面講到的植入資源文件}

在sync后BuildConfig中就有你定義的這個(gè)變量了。

public finalclassBuildConfig{? publicstaticfinal boolean DEBUG =Boolean.parseBoolean("true");? publicstaticfinalStringAPPLICATION_ID ="kale.gradle.test";? publicstaticfinalStringBUILD_TYPE ="debug";? publicstaticfinalStringFLAVOR ="";? publicstaticfinal int VERSION_CODE =1;? publicstaticfinalStringVERSION_NAME ="1.0.0";// Fields from default config.publicstaticfinal boolean IS_KALE_TEST =true;}

如果有帶引號(hào)的string甩鳄,要記得轉(zhuǎn)義:

buildConfigField"String","URL_ENDPOINT","\"http://your.development.endpoint.com/\""

init.with

如果我們想要新增加一個(gè)buildType逞度,又想要新的buildType繼承之前配置好的參數(shù),init.with()就很適合你了妙啃。

buildTypes {? ? ? ? release {? ? ? ? ? ? zipAlignEnabledtrueminifyEnabledtrueshrinkResourcestrue// 是否去除無效的資源文件proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.txt'signingConfig signingConfigs.release? ? ? ? }? ? ? ? rtm.initWith(buildTypes.release)// 繼承release的配置rtm {}? ? }

多個(gè)flavor

flavor可以定義不同的產(chǎn)品場景档泽,我們?cè)谥暗奈恼轮幸呀?jīng)多次講到了這個(gè)屬性,下面就是一個(gè)在dev的時(shí)候提升支持的android最低版本的做法揖赴。

productFlavors {// 自定義flavordev {? ? ? ? minSdkVersion21}}

flavor的一大優(yōu)點(diǎn)是可以通過as來動(dòng)態(tài)的改變這個(gè)值馆匿,不用硬編碼:

如果你定義了不同的flavor,可以在目錄結(jié)構(gòu)上針對(duì)不同的flavor定義不同的文件資源燥滑。

productFlavors{

dev {}

dev2 {}

qihu360{}

yingyongbao{}

}

定義局部變量

有時(shí)候一個(gè)庫會(huì)被引用多次渐北,或者一個(gè)庫有多個(gè)依賴,但這些依賴的版本都是統(tǒng)一的突倍。我們通過ext來定義一些變量腔稀,這樣在用到的時(shí)候就可以統(tǒng)一使用了盆昙。

ext {? ? leakcanaryVersion ='1.3.1'scalpelVersion ="1.1.2"http:// other param}

debugCompile"com.squareup.leakcanary:leakcanary-android:$leakcanaryVersion"releaseCompile"com.squareup.leakcanary:leakcanary-android-no-op:$leakcanaryVersion"

exlude關(guān)鍵字

我們經(jīng)常會(huì)遇到庫沖突的問題,這個(gè)在多個(gè)部門協(xié)作的大公司會(huì)更常見到焊虏。將沖突的庫通過exclude來做剔除是一個(gè)好方法淡喜。

剔除整個(gè)組織的庫

compile ('com.facebook.fresco:animated-webp:0.13.0') { exclude group:'com.android.support'// 僅僅寫組織名稱}

剔除某個(gè)庫

compile('com.android.support:appcompat-v7:23.2.0') {? ? exclude group:'com.android.support',module:'support-annotations'// 寫全稱exclude group:'com.android.support',module:'support-compat'exclude group:'com.android.support',module:'support-v4'exclude group:'com.android.support',module:'support-vector-drawable'}

聚合依賴多個(gè)庫

有時(shí)候一些庫是一并依賴的,剔除也是要一并剔除的诵闭,我們可以像下面這樣進(jìn)行統(tǒng)一引入:

compile(['com.github.tianzhijiexian:logger:2e5da00f0f','com.jakewharton.timber:timber:4.1.2'])

這樣別的開發(fā)者就知道哪些庫是有相關(guān)性的炼团,在下掉庫的時(shí)候也比較方便。

剔除task

Gradle每次構(gòu)建時(shí)都執(zhí)行了許多的task疏尿,其中或許有一些task是我們不需要的瘟芝,可以把它們都屏蔽掉,方法如下:

tasks.whenTaskAdded { task ->if(task.name.contains('AndroidTest') || task.name.contains('Test')) {? ? ? ? task.enabled =false}}

這樣我們就會(huì)在build時(shí)跳過包含AndroidTest和Test關(guān)鍵字的task了褥琐。

ps:有時(shí)候我們自己也會(huì)寫一些task或者引入一些gradle插件和task锌俱,通過這種方式可以簡單的進(jìn)行選擇性的執(zhí)行(下文會(huì)將如何寫邏輯判斷)。

通過邏輯判斷來跳過task

我們上面有提到動(dòng)態(tài)獲得字段的技巧敌呈,但有些東西是在打包發(fā)版的時(shí)候用贸宏,有些則是在調(diào)試時(shí)用,我們需要區(qū)分不同的場景磕洪,定義不同的task吭练。我下面以通過“用git的commit號(hào)做版本號(hào)”這個(gè)需求做例子。

def cmd ='git rev-list HEAD --first-parent --count'def gitVersion = cmd.execute().text.trim().toInteger()android {? defaultConfig {? ? versionCode gitVersion? }}

因?yàn)樯厦娴牟僮骺赡鼙容^慢析显,或者在debug時(shí)沒必要鲫咽,所以我們就做了如下判斷:

def gitVersion() {if(!System.getenv('CI_BUILD')) {// 不通過CI進(jìn)行build的時(shí)候返回01// don't carereturn1}? def cmd ='git rev-list HEAD --first-parent --count'cmd.execute().text.trim().toInteger()}android {? defaultConfig {? ? versionCode gitVersion()? }}

這里用到了System.getenv()方法,你可以參考java中System下的getenv()來理解谷异,就是得到當(dāng)前的環(huán)境分尸。

引用全局的配置文件

在根目錄中建立一個(gè)config.gradle文件:

ext {? ? android = [? ? ? ? ? ? compileSdkVersion:23,applicationId:"com.kale.gradle",? ? ]? ? dependencies = ["support-v4":"com.android.support:appcompat-v7:24.2.1",? ? ]}

然后在根目錄的build.gradle中引入apply from: "config.gradle",即:

// Top-level build file where you can add configuration options common to all sub-projects/modules.applyfrom:"config.gradle"http:// 引入該文件buildscript {? ? repositories {? ? ? ? jcenter()? ? }? ? dependencies {? ? ? ? classpath'com.android.tools.build:gradle:2.2.2'}// ...}

之后就可以在其余的gradle中讀取變量了:

defaultConfig {? ? applicationId rootProject.ext.android.applicationId// 引用applicationIdminSdkVersion14targetSdkVersion20}dependencies {? ? compile rootProject.ext.dependencide["support-v7"]// 引用dependencide}

區(qū)分不同環(huán)境下的不同依賴

我們除了可以通過buildtype來定義不同的依賴外歹嘹,我們還可以通過寫邏輯判斷來做:

dependencies {//根據(jù)是不同情形進(jìn)行判斷if(!needMultidex) {? ? ? ? provided fileTree(dir:'libs',include: ['*.jar'])? ? }else{? ? ? ? compile'com.android.support:multidex:1.0.0'}// ...}

動(dòng)態(tài)改變module種類

插件化有可能會(huì)要根據(jù)環(huán)境更改當(dāng)前module是app還是lib寓落,gradle的出現(xiàn)讓其成為了可能。

if(isDebug.toBoolean()) {? ? apply plugin:'com.android.application'}else{? ? apply plugin:'com.android.library'}

接下來只需要在gradle.properties中寫上:

isDebug =false

需要說明的是:根據(jù)公司和插件化技術(shù)的不同荞下,此方法因人而異。

定義庫的私有混淆

有很多庫是需要進(jìn)行混淆配置的史飞,但讓使用者配置混淆文件的方式總是不太友好尖昏,consumerProguardFiles的出現(xiàn)可以讓庫作者在庫中定義混淆參數(shù),讓混淆配置對(duì)使用者屏蔽构资。

ShareLoginLib中的例子:

apply plugin:'com.android.library'android {? ? compileSdkVersion24buildToolsVersion'24.0.2'defaultConfig {? ? ? ? minSdkVersion9targetSdkVersion24consumerProguardFiles'consumer-proguard-rules.pro'// 自定義混淆配置}? ? buildTypes {? ? ? ? release {? ? ? ? ? ? minifyEnabledfalseproguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'}? ? }}

realm也用到了這樣的配置:

打包工具會(huì)將*.pro文件打包進(jìn)入aar中抽诉,庫混淆時(shí)候會(huì)自動(dòng)使用此混淆配置文件。

以consumerProguardFiles方式加入的混淆具有以下特性:

*.pro文件會(huì)包含在aar文件中

這些pro配置會(huì)在混淆的時(shí)候被使用

此配置針對(duì)此aar進(jìn)行混淆配置

此配置只對(duì)庫文件有效吐绵,對(duì)應(yīng)用程序無效

如果你對(duì)于consumerProguardFiles有疑問迹淌,可以去ConsumerProGuardFilesTest這個(gè)項(xiàng)目了解更多河绽。

指定資源目錄

android {? ? sourceSets {? ? ? ? main {? ? ? ? ? ? manifest.srcFile'AndroidManifest.xml'java.srcDirs = ['src']? ? ? ? ? ? resources.srcDirs = ['src']? ? ? ? ? ? aidl.srcDirs = ['src']? ? ? ? ? ? renderscript.srcDirs = ['src']? ? ? ? ? ? assets.srcDirs = ['assets']if(!IS_USE_DATABINDING) {// 如果用了databindingjniLibs.srcDirs = ['libs']? ? ? ? ? ? ? ? res.srcDirs = ['res','res-vm']// 多加了databinding的資源目錄}else{? ? ? ? ? ? ? ? res.srcDirs = ['res']? ? ? ? ? ? }? ? ? ? }? ? ? ? test {? ? ? ? ? ? java.srcDirs = ['test']? ? ? ? }? ? ? ? androidTest {? ? ? ? ? ? java.srcDirs = ['androidTest']? ? ? ? }? ? }}

通過上面的配置,我們可以自定義java代碼和res資源的目錄唉窃,一個(gè)和多個(gè)都沒有問題耙饰,更加靈活(layout文件分包也是利用了這個(gè)知識(shí)點(diǎn))。

定義多個(gè)Manifest

sourceSets {? ? main {if(isDebug.toBoolean()) {? ? ? ? ? ? manifest.srcFile'src/debug/AndroidManifest.xml'}else{? ? ? ? ? ? manifest.srcFile'src/release/AndroidManifest.xml'}? ? }}

根據(jù)flavor也可以進(jìn)行定義:

productFlavors {? ? hip {? ? ? ? manifest.srcFile'hip/AndroidManifest.xml'}? ? main {? ? ? ? manifest.srcFile'/AndroidManifest.xml'}}

Force

force強(qiáng)制設(shè)置某個(gè)模塊的版本纹份。

configurations.all {

resolutionStrategy {

force 'org.hamcrest:hamcrest-core:1.3'

}

}

dependencies {

androidTestCompile('com.android.support.test:runner:0.2')

androidTestCompile('com.android.support.test:rules:0.2')

androidTestCompile('com.android.support.test.espresso:espresso-core:2.1')

}

可以看到苟跪,原本對(duì)hamcrest-core 1.1的依賴,全部變成了1.3蔓涧。

Exclude可以設(shè)置不編譯指定的模塊

configurations {

all*.exclude group: 'org.hamcrest', module: 'hamcrest-core'

}

dependencies {

androidTestCompile('com.android.support.test:runner:0.2')

androidTestCompile('com.android.support.test:rules:0.2')

androidTestCompile('com.android.support.test.espresso:espresso-core:2.1')

}

單獨(dú)使用group或module參數(shù)

exclude后的參數(shù)有g(shù)roup和module件已,可以分別單獨(dú)使用,會(huì)排除所有匹配項(xiàng)元暴。例如下面的腳本匹配了所有的group為’com.android.support.test’的模塊篷扩。

configurations {

all*.exclude group: 'com.android.support.test'

}

dependencies {

androidTestCompile('com.android.support.test:runner:0.2')

androidTestCompile('com.android.support.test:rules:0.2')

androidTestCompile('com.android.support.test.espresso:espresso-core:2.1')

}

總結(jié)

gradle的最佳實(shí)踐是最好寫也是相當(dāng)難寫的。好寫之處在于都是些約定俗成的配置項(xiàng)茉盏,而且寫法固定鉴未;難寫之處在于很難系統(tǒng)性的解釋和說明它在實(shí)際中的意義。因?yàn)樗`活了援岩,可以做的事情太多了歼狼,用法還是交給開發(fā)者來擴(kuò)展吧。

當(dāng)年從eclipse切到android studio時(shí)享怀,gradle沒少給我添麻煩羽峰,也正是因?yàn)檫@些麻煩和不斷的填坑積累,給我了上述的多個(gè)實(shí)踐經(jīng)驗(yàn)添瓷。

從寫demo到正式項(xiàng)目梅屉,從正式項(xiàng)目做到開發(fā)庫,從開發(fā)庫做到組件化鳞贷,這一步步的走來都少不了gradle這個(gè)魔鬼坯汤。今天我將我一年內(nèi)學(xué)到的和真正使用過的東西分享在此,希望大家除了獲益以外搀愧,還能真的將gradle視為敵人和友人惰聂,去多多了解這個(gè)家伙

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市咱筛,隨后出現(xiàn)的幾起案子搓幌,更是在濱河造成了極大的恐慌,老刑警劉巖迅箩,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溉愁,死亡現(xiàn)場離奇詭異,居然都是意外死亡饲趋,警方通過查閱死者的電腦和手機(jī)拐揭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門撤蟆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人堂污,你說我怎么就攤上這事家肯。” “怎么了敷鸦?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵息楔,是天一觀的道長。 經(jīng)常有香客問我扒披,道長值依,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任碟案,我火速辦了婚禮愿险,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘价说。我一直安慰自己辆亏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布鳖目。 她就那樣靜靜地躺著扮叨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪领迈。 梳的紋絲不亂的頭發(fā)上彻磁,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音狸捅,去河邊找鬼衷蜓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尘喝,可吹牛的內(nèi)容都是我干的磁浇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼朽褪,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼置吓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缔赠,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤交洗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后橡淑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咆爽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年梁棠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了置森。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡符糊,死狀恐怖凫海,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情男娄,我是刑警寧澤行贪,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站模闲,受9級(jí)特大地震影響建瘫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尸折,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一啰脚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧实夹,春花似錦橄浓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至缴淋,卻和暖如春准给,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宴猾。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工圆存, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仇哆。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓沦辙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親讹剔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子油讯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,434評(píng)論 2 45
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,162評(píng)論 25 707
  • 世界上最能體現(xiàn)愛的延欠,莫過于夫妻之間陌兑,父母與子女之間, 夫妻由捎,夫妻沒結(jié)婚之前兔综,首先是讓雙方互相的吸引的,或者是容貌,...
    海望閱讀 273評(píng)論 0 2
  • 文/清雅 聽一段音樂如同凝望一縷云煙软驰,縹緲萬狀虛無涧窒,一直飄啊蕩向高處。 倚在窗前锭亏,感慨夜的迷離和深邃纠吴,...
    清雅怡然閱讀 871評(píng)論 0 2
  • 今天從上海開車到美麗的宜興參加朋友的婚禮,看著一對(duì)新人伴隨著莊嚴(yán)的婚禮進(jìn)行曲慧瘤,在司儀的聲聲祝福與調(diào)侃中戴已、在伴...
    蓮花山的小薇閱讀 800評(píng)論 3 13