Android中Gradle常用配置

文/ZYRzyr
原文鏈接:http://www.reibang.com/p/7ca459085b96

2017年08月15日更新浅妆,不知道簡書出什么BUG了凌外,重新發(fā)布更新一下,原來的目錄標(biāo)簽全部失效變成文字了摄欲,無奈之下只有刪掉胸墙,簡直坑爹迟隅,待過幾日再看能否重新啟用目錄。

前言

本文記錄了一些常用的gradle配置奔缠,基本上都是平時(shí)開發(fā)中可能會(huì)使用到的校哎,如果有新內(nèi)容會(huì)不定時(shí)更新箫锤,附官網(wǎng)

1.依賴庫版本寫法
  • 不推薦寫法:
dependencies {
    compile 'com.example.code.abc:def:2.+' // 不推薦的寫法
}

這樣寫雖然可能保證每次都保持庫是最新的谚攒,但同時(shí)會(huì)有以下更嚴(yán)重的問題
1)多人開發(fā)時(shí)馏臭,每個(gè)人可能會(huì)得到不同的最新版本括儒,帶來潛在的隱患锐想;
2)庫更新后赠摇,可能會(huì)由于庫的內(nèi)部代碼的修改而引起不易發(fā)現(xiàn)的BUG藕帜;
3)每次build時(shí)會(huì)聯(lián)網(wǎng)檢查洽故,增加build時(shí)間。

  • 推薦寫法(固定版本):
dependencies {
    compile 'com.example.code.abc:def:2.0.1' // 固定版本隘弊,有需要時(shí)再進(jìn)行修改
}
2.全局設(shè)置編碼

在最頂層的build.gradle中添加:

allprojects {
    repositories {
        jcenter()
    }

    tasks.withType(JavaCompile){
        options.encoding = "UTF-8"
    }
}
3.設(shè)置Java編譯版本

module中的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
    }
}
4.Release版本的密碼配置

密碼嚣鄙、簽名等敏感信息可以統(tǒng)一進(jìn)行存放串结,不進(jìn)行硬編碼肌割。寫在gradle.properies中把敞,可以隨意的定義key-value形式奋早,此文件是gradle自動(dòng)引入的。
例:gradle.properies文件如下

STORE_FILE_PATH ../test_key.jks
KEYSTORE_PASSWORD 123456
KEY_ALIAS abc
KEY_PASSWORD 654321
PACKAGE_NAME_SUFFIX .test
TENCENT_AUTHID aaa0123

modulebuild.gradle文件:

signingConfigs {
    release {
        try {
              storeFile file(STORE_FILE_PATH)
              storePassword STORE_PASSWORD
              keyAlias KEY_ALIAS
              keyPassword KEY_PASSWORD
        }
        catch (ex) {
            throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
        }
    }
}
5.設(shè)置第三方maven倉庫

在頂層的build.gradle中:

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

其中name和credentials是可選項(xiàng),視具體情況而定规个。如使用阿里云倉庫如下:

allprojects {
    repositories {
        maven { 
           url "http://maven.aliyun.com/nexus/content/groups/public/" 
       }
    }
}
6.自動(dòng)刪除unaligned apk

每次打包后都會(huì)有一個(gè)unaligned的apk文件生成诞仓,這個(gè)文件對(duì)于開發(fā)來說無意義速兔,可以配置一個(gè)task來刪除它涣狗。
寫在modulebuild.gradle中:

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
}
android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        // 刪除unaligned apk
        if (output.zipAlign != null) {
            output.zipAlign.doLast {
                output.zipAlign.inputFile.delete()
            }
        }
    }
}
7.lint選項(xiàng)開關(guān)

lint默認(rèn)會(huì)做嚴(yán)格檢查屑柔,遇到包錯(cuò)誤會(huì)終止構(gòu)建過程掸宛。可以用如下開關(guān)關(guān)掉這個(gè)選項(xiàng)别凤,非特殊情況不最好不配置领虹。
寫在modulebuild.gradle中:

android {
    lintOptions {
        disable 'InvalidPackage'
        checkReleaseBuilds false
        abortOnError false
    }
}
8.依賴項(xiàng)目中的module和jar

工程可以依賴自身的module和jar文件塌衰,如下:

dependencies {
    compile project(':myExamplelibraryModule')
    compile files('libs/sdk-1.1.jar')
}
9.根據(jù)buildType設(shè)置包名

寫在modulebuild.gradle中:

android {
    defaultConfig {
        applicationId "example" // 這里設(shè)置了example作為默認(rèn)包名
    }

    buildTypes {
        release {
            applicationIdSuffix '.abc.gradle' // 設(shè)置release時(shí)的包名為example.abc.gradle
        }
        debug{
            applicationIdSuffix '.abc.debug' // 設(shè)置debug時(shí)的包名為example.abc.debug
        }
    }
10.替換AndroidManifest中的占位符

在manifest中可以有類似{appName}這樣的占位符杯巨,在modulebuild.gradle中可以將其進(jìn)行賦值努酸。

android{
    defaultConfig{
        manifestPlaceholders = [appName:"@string/app_name"]
    }
}
11.定義全局變量

先在頂層的build.gradle定義全局變量:

ext {
    minSdkVersion = 19
    targetSdkVersion = 24
}

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

android {
    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
    }
}

如果是在當(dāng)前文件中定義的获诈,就不用添加rootProject.ext舔涎。

12.定義局部變量

有時(shí)候一個(gè)庫會(huì)被引用多次终抽,或者一個(gè)庫有多個(gè)依賴昼伴,但這些依賴的版本都是統(tǒng)一的镣屹。通過ext來定義一些變量女蜈,這樣在用到的時(shí)候就可以統(tǒng)一使用了:

ext {
    rxandroidVersion = '2.0.1'
    rxjavaVersion = "2.1.0"
}

dependencies {
      ...
      compile "io.reactivex.rxjava2:rxandroid:$rxandroidVersion"
      compile "io.reactivex.rxjava2:rxjava:$rxjavaVersion"
}
13.動(dòng)態(tài)設(shè)置額外信息

假如想把當(dāng)前的編譯時(shí)間伪窖、編譯的機(jī)器覆山、最新的commit版本添加到apk中,動(dòng)態(tài)設(shè)置如下:

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

上述代碼實(shí)現(xiàn)了動(dòng)態(tài)添加了3個(gè)字符串資源: build_time吧享、build_host钢颂、build_revision, 在其他地方可像引用strings.xml中的字符串一樣使用:

getString(R.string.build_time)  // 輸出2017-06-12 15:05:05
getString(R.string.build_host)  // 輸出zyr@example殊鞭,這是我的電腦的用戶名和PC名
getString(R.string.build_revision) // 輸出5ff4x89, 這是最后一次commit的sha值

上面講到的是植入資源文件尼桶,同樣可以在BuildConfig.class中增加自己的靜態(tài)變量:

defaultConfig {
    applicationId "zyr.gradle.demo"
    minSdkVersion 19
    targetSdkVersion 24

    buildConfigField("boolean", "IS_TEST", "true") // 定義一個(gè)bool變量

    resValue "string", "build_time", "2017.06.12" // 上面講到的植入資源文件
}

syncBuildConfig中就有定義的這個(gè)變量了:

public final class BuildConfig {
      public static final boolean DEBUG = Boolean.parseBoolean("true");
      public static final String APPLICATION_ID = "zyr.gradle.test";
      public static final String BUILD_TYPE = "debug";
      public static final String FLAVOR = "";
      public static final int VERSION_CODE = 1;
      public static final String VERSION_NAME = "1.0.0";

      // Fields from default config.
      public static final boolean IS_TEST = true;
}

如果有帶引號(hào)的string牲尺,需要轉(zhuǎn)義:

 buildConfigField "String", "URL_ENDPOINT", "\"http://your.development.example.com/\""
14.使用init.with繼承配置

如果想新增一個(gè)buildType谤碳,又想新的buildType繼承之前配置好的參數(shù)蜒简,使用init.with()漩仙。

buildTypes {
        release {
            zipAlignEnabled true
            minifyEnabled true
            shrinkResources true // 是否去除無效的資源文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            signingConfig signingConfigs.release
        }

        abcd.initWith(buildTypes.release) // 繼承release的配置
        abcd {
             ...
        }
    }
15.exlude關(guān)鍵字

遇到庫沖突的問題時(shí)卷仑,將沖突的庫通過exclude來剔除:

  • 剔除整個(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'
}
16.聚合依賴多個(gè)庫

有時(shí)候一些庫是一并依賴的锡凝,剔除也是要一并剔除的窜锯,此時(shí)進(jìn)行統(tǒng)一引入:

compile(['io.reactivex.rxjava2:rxandroid:2.0.1',
           'io.reactivex.rxjava2:rxjava:2.1.0'])

這樣別的開發(fā)者就知道哪些庫是有相關(guān)性的锚扎,在刪除庫的時(shí)候也更方便馁启。

17.跳過task

Gradle每次構(gòu)建時(shí)都執(zhí)行了許多task,其中有一些task是不需要的浪听,可以把它們都屏蔽掉迹栓,如下:

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

這樣在build時(shí)就會(huì)跳過包含AndroidTest和Test關(guān)鍵字的task了克伊。
NOTE:有時(shí)候自己也會(huì)寫一些task或者引入一些gradle插件和task愿吹,通過這種方式可以簡單的進(jìn)行選擇性的執(zhí)行犁跪。

18.通過邏輯判斷來跳過task

上面有提到過動(dòng)態(tài)獲得字段歹袁,但有些東西是在打包發(fā)布的時(shí)候用条舔,有些則是在調(diào)試時(shí)用孟抗,需要區(qū)分不同的場景凄硼,定義不同的task帆喇。下面以通過“以gitcommit號(hào)當(dāng)做版本號(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í)候返回1
          return 1    //1無實(shí)際意義,return用于中斷后續(xù)操作
      }
      def cmd = 'git rev-list HEAD --first-parent --count'
      cmd.execute().text.trim().toInteger()
}
android {
      defaultConfig {
        versionCode gitVersion()
      }
}

這里用到了System.getenv()方法序仙,可以參考JavaSystem下的getenv()突颊,就是得到當(dāng)前的環(huán)境。

19.引用全局的配置文件

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

ext {
    android = [
            compileSdkVersion: 23,
            applicationId    : "com.zyr.gradle",
    ]

    dependencies = [
            "support-v7": "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.
apply from: "config.gradle" // 引入該文件
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
    // ...
}

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

defaultConfig {
      applicationId rootProject.ext.android.applicationId // 引用applicationId
      minSdkVersion 14
      targetSdkVersion 20
}
dependencies {
      compile rootProject.ext.dependencide["support-v7"] // 引用dependencide
}
20.區(qū)分不同環(huán)境下的不同依賴

除了通過buildtype來定義不同的依賴外律秃,還可以通過寫邏輯判斷來做:
先在gradle.properties中寫上:
needExample = true
然后在modulebuild.gradle中使用:

dependencies {
    //根據(jù)是不同情形進(jìn)行判斷
    if (!needExample) {
        provided fileTree(dir: 'libs', include: ['*.jar'])
    } else {
        compile 'com.android.support:example:1.0.0'
    }
    // ...
}
21.動(dòng)態(tài)改變module種類

插件化有可能會(huì)要根據(jù)環(huán)境更改當(dāng)前module是app還是lib:
先在gradle.properties中寫上:
isDebug = false
然后在modulebuild.gradle中使用:

if (isDebug.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
22.定義庫的私有混淆(針對(duì)庫的開發(fā))

有很多庫是需要進(jìn)行混淆配置的爬橡,但讓庫的使用者配置混淆文件的方式總是不太友好,consumerProguardFiles可以讓庫的作者在庫中定義混淆參數(shù)棒动,讓使用者無需了解其混淆:

apply plugin: 'com.android.library'
android {
    compileSdkVersion 24
    buildToolsVersion '24.0.2'

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 24
        consumerProguardFiles 'consumer-proguard-rules.pro' //  自定義混淆配置
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

其中的consumer-proguard-rules.pro文件位置如下圖:

consumerProguardFiles.jpg

打包工具會(huì)將*.pro文件打包進(jìn)入aar中,庫混淆的時(shí)候會(huì)自動(dòng)使用此混淆配置文件船惨。
consumerProguardFiles方式加入的混淆具有以下特性:

  • *.pro文件會(huì)包含在aar文件中
  • 這些pro配置會(huì)在混淆的時(shí)候被使用
  • 此配置針對(duì)此aar進(jìn)行混淆配置
  • 此配置只對(duì)庫文件(apply plugin: 'com.android.library)有效柜裸,對(duì)應(yīng)用程序(apply plugin: 'com.android.application')無效
23.指定資源目錄

modulebuild.gradle中通過下面的配置,可以自定義java代碼和res資源的目錄粱锐,一個(gè)和多個(gè)都可以疙挺,更加靈活:

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) { // 如果用了databinding
                jniLibs.srcDirs = ['libs']
                res.srcDirs = ['res', 'res-vm'] // 多加了databinding的資源目錄
            } else {
                res.srcDirs = ['res']
            }
        }

        test {
            java.srcDirs = ['test']
        }

        androidTest {
            java.srcDirs = ['androidTest']
        }
    }
}
24.定義多個(gè)Manifest

modulebuild.gradle中:

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

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

productFlavors {
    abc {
        manifest.srcFile 'abc/AndroidManifest.xml'
    }

    main {
        manifest.srcFile '/AndroidManifest.xml'
    }
}
最后

gradle可以做很多事,也非常靈活怜浅。希望上面提到的一些配置對(duì)大家有所幫助铐然。有空去官網(wǎng)了解最好。
吐糟一句恶座,簡書的markdown真?難用=蹙簟!

原文作者/ZYRzyr
原文鏈接:http://www.reibang.com/p/7ca459085b96

請(qǐng)進(jìn)入這里獲取授權(quán):https://101709080007647.bqy.mobi

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奥裸,一起剝皮案震驚了整個(gè)濱河市险掀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌湾宙,老刑警劉巖樟氢,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異侠鳄,居然都是意外死亡埠啃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門伟恶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碴开,“玉大人,你說我怎么就攤上這事博秫×逝#” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵挡育,是天一觀的道長巴碗。 經(jīng)常有香客問我,道長即寒,這世上最難降的妖魔是什么橡淆? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任召噩,我火速辦了婚禮,結(jié)果婚禮上逸爵,老公的妹妹穿的比我還像新娘具滴。我一直安慰自己,他們只是感情好师倔,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布构韵。 她就那樣靜靜地躺著,像睡著了一般溯革。 火紅的嫁衣襯著肌膚如雪贞绳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天致稀,我揣著相機(jī)與錄音冈闭,去河邊找鬼。 笑死抖单,一個(gè)胖子當(dāng)著我的面吹牛萎攒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播矛绘,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼耍休,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了货矮?” 一聲冷哼從身側(cè)響起羊精,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎囚玫,沒想到半個(gè)月后喧锦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抓督,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡阵具,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趁舀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祝沸。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖奉狈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跛蛋,我是刑警寧澤赊级,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏牺蹄。R本人自食惡果不足惜氓奈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一育勺、第九天 我趴在偏房一處隱蔽的房頂上張望涧至。 院中可真熱鬧,春花似錦窄陡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽套硼。三九已至卡辰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邪意,已是汗流浹背九妈。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雾鬼,地道東北人萌朱。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像策菜,于是被迫代替她去往敵國和親晶疼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,744評(píng)論 25 707
  • Gradle配置最佳實(shí)踐 本文會(huì)不定期更新又憨,推薦watch下項(xiàng)目翠霍。如果喜歡請(qǐng)star,如果覺得有紕漏請(qǐng)?zhí)峤籭ssu...
    Solang閱讀 1,629評(píng)論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蠢莺,服務(wù)發(fā)現(xiàn)寒匙,斷路器,智...
    卡卡羅2017閱讀 134,628評(píng)論 18 139
  • 1.這款插件以來jquery.js躏将,所以首先要引用jquery文件 2.要有img標(biāo)簽 圖片的真實(shí)路徑要寫在dat...
    雨魚魚兒閱讀 463評(píng)論 0 2
  • 1 去年,我身邊的一位朋友永遠(yuǎn)離開了這個(gè)世界棵癣,享年31歲辕翰,卵巢癌夺衍。 直到現(xiàn)在狈谊,我依然不想接受這個(gè)事實(shí)。好像昨天我還...
    婉悅悠然閱讀 781評(píng)論 17 17