Android Gradle學(xué)習(xí)(九):有用的小技巧

現(xiàn)在的Android工程都是采用 gradle 來(lái)構(gòu)建的,從早期的單一工程架構(gòu)(一個(gè)項(xiàng)目只有一個(gè)主 module)晒衩,到現(xiàn)在的組件化架構(gòu)(一個(gè)項(xiàng)目包含有多個(gè)module)增淹,項(xiàng)目結(jié)構(gòu)越來(lái)越復(fù)雜膛堤,在這里陸續(xù)記錄一些挺有用的小技巧奋构。

1. resolutionStrategy 統(tǒng)一全局第三方庫(kù)版本

resolutionStrategy 顧名思義“解析策略”壳影,也就是說(shuō)可以在 gradle 解析各種依賴庫(kù)時(shí),配置一些解析策略弥臼。

1.1 resolutionStrategy.force

我們?cè)陂_(kāi)發(fā)的過(guò)程當(dāng)中宴咧,會(huì)依賴使用各種第三方庫(kù),比如說(shuō)最常見(jiàn)的 appcompat-v7 庫(kù)径缅,不僅我們自己的代碼里會(huì)依賴該庫(kù)掺栅,而且有可能我們依賴的第三方庫(kù)也會(huì)依賴該庫(kù),但是不同的地方依賴該庫(kù)的版本號(hào)都有可能不一致纳猪,這樣在編譯的時(shí)候氧卧,整個(gè)項(xiàng)目當(dāng)中會(huì)出現(xiàn)各種不同版本號(hào)的 appcompat-v7 庫(kù),編譯的時(shí)候可能會(huì)報(bào)錯(cuò)氏堤。我們不可能修改第三方庫(kù)里對(duì) appcompat-v7 庫(kù)依賴的版本號(hào)沙绝,那么我們可以通過(guò) resolutionStrategy.force 來(lái)強(qiáng)制編譯時(shí)統(tǒng)一庫(kù)的版本號(hào)。

android {
    configurations.all {
        resolutionStrategy {
            force 'com.android.support:appcompat-v7:28.0.0'
            force 'com.android.support:support-v4:28.0.0'
        }
    }
}

1.2 resolutionStrategy.dependencySubstitution

還有一種這樣的情形,假設(shè)一個(gè)第三方工具庫(kù)叫 org.gradle:util:3.0宿饱,除了我們自己的項(xiàng)目以及部分第三方庫(kù)也有依賴它熏瞄,但是在實(shí)際使用的過(guò)程當(dāng)中脚祟,發(fā)現(xiàn)該庫(kù)有些功能不滿足或者有bug谬以,那這個(gè)時(shí)候該怎么辦呢?一是提 issue 讓該庫(kù)的作者去修改由桌,但是時(shí)間上來(lái)不及为黎;二是源碼拿過(guò)來(lái)本地進(jìn)行修改,直接本地集成行您,但是要修改依賴方式铭乾,那么這個(gè)時(shí)候可以這樣做:

假設(shè)我們本地 module 名稱叫 :util

android {
    configurations.all {
        resolutionStrategy {
            //遠(yuǎn)程依賴替換成本地依賴
            substitute module('org.gradle:util:3.0') with project(':util')
            //也可以將遠(yuǎn)程依賴換成另外的遠(yuǎn)程依賴,假設(shè)我們修改過(guò)的代碼發(fā)布到自己的 maven 中央倉(cāng)庫(kù)后叫:com.xxx.xxx:util:3.0
            //substitute module('org.gradle:util:3.0') with module('com.xxx.xxx:util:3.0') 
        }
    }
}

2. gradle.settingsEvaluated 在編譯之前做一些初始化工作

之前接手過(guò)一個(gè)項(xiàng)目娃循,是采用 react-native 框架進(jìn)行開(kāi)發(fā)的炕檩,熟悉前端以及 React 的同學(xué)都知道,項(xiàng)目 build 的第一步是先進(jìn)行 npm install 或者 yarn 操作捌斧,這樣所有依賴的第三方庫(kù)都會(huì)下載到 node_modules 目錄下面笛质。在 react-native 當(dāng)中,Android 工程會(huì)依賴 node_modules 目錄下的原生 Android 代碼捞蚂,但是因?yàn)閹?kù)的版本關(guān)系妇押,每次我編譯的時(shí)候,都會(huì)發(fā)現(xiàn)某個(gè) module 中的 build.gradle 配置與主工程沖突姓迅,需要手動(dòng)修改才能編譯敲霍。需要注意的是,node_modules 目錄是動(dòng)態(tài)下載的第三方庫(kù)丁存,并不會(huì)被提交肩杈,也就是說(shuō)每次執(zhí)行 yarn 操作之后再編譯 Android,都需要手動(dòng)更改下這個(gè)目錄下的庫(kù)解寝,非常繁瑣扩然。那么有沒(méi)方法來(lái)自動(dòng)幫我們解決這個(gè)問(wèn)題,不用每次都要手動(dòng)修改呢编丘?答案是可以与学。gradle 有個(gè)生命周期鉤子方法 gradle.settingsEvaluated,在 gradle configure 階段之前讓我們做一些處理嘉抓。

在我們項(xiàng)目的 settings.gradle 文件的最開(kāi)頭加上該方法的監(jiān)聽(tīng)索守,注意該方法必須加在 settings.gradle 文件中,在 build.gradle 里沒(méi)用抑片。以下是個(gè)范例:

gradle.settingsEvaluated {
    println "-------------settingsEvaluated start------------"
    //假設(shè)我們要修改的是 react-native-fs 這個(gè)庫(kù)當(dāng)中的 build.gradle 文件
    //先刪除該文件
    delete("${rootDir}/../node_modules/react-native-fs/android/build.gradle")
    //我們將修改好的文件放到 ./replace-files/react-native-fs 這個(gè)目錄當(dāng)中
    //前面已經(jīng)刪除了目標(biāo)文件卵佛,現(xiàn)在只需將我們需要的文件復(fù)制過(guò)去即可
    copy {
        from("./replace-files/react-native-fs/build.gradle")
        into("${rootDir}/../node_modules/react-native-fs/android")
    }
    println "-------------settingsEvaluated end------------"
}

執(zhí)行打包命令 ./gradlew assembleRelease 等的時(shí)候,一開(kāi)始就會(huì)執(zhí)行以上代碼,自動(dòng)幫我們做好這些事情截汪。

除此之外疾牲,還可以做很多事情,比如打包前先刪除某個(gè)緩存目錄的文件衙解,每次打包時(shí)自動(dòng)遞增修改 versionCode阳柔、versionName ,檢查 local.properties 配置文件是否存在已經(jīng)配置是否正確等等蚓峦。

3. 修改包的輸出路徑

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def date = releaseTime()
            //這里只改變 release 包的輸出路徑
            if (variant.buildType.name.contains('release')) {
                //我們定義包的輸出路徑為 android_outputs/Android_APK
                //這里可以根據(jù)情況定義任意路徑
                variant.packageApplicationProvider.get().outputDirectory = new File(project.rootDir.absolutePath + File.separator + "android_outputs"+ File.separator + "Android_APK")
                //包名范例:Android-pro-release-v2.6.6-c266-d202108181428.apk
                def fileName = "Android-${variant.productFlavors[0].name}-${buildType.name}-v" + versionName + "-c" + versionCode + "-d" + date + ".apk"
                output.outputFileName = fileName
            }

            //拓展一下舌剂,也可以根據(jù) productFlavors 來(lái)做配置
            /*
            if (variant.getName() == "qaRelease") {
                //這里還可以動(dòng)態(tài)修改 productFlavors 里的東西,例如:
                variant.buildConfigField "String", "APP_CHANNEL", '"xiaomi"'
            } else if (variant.getName() == "proRelease") {                

            }
            */
        }
    }
}

def releaseTime() {
    return new Date().format("yyyyMMddHHmm")
}

4. 找到版本沖突的庫(kù)

當(dāng)項(xiàng)目越來(lái)越大暑椰,所使用的第三方庫(kù)越來(lái)越多的時(shí)候霍转,最讓人頭疼的是針對(duì)同一個(gè)庫(kù)引入了多個(gè)不同的版本,編譯的時(shí)候?qū)е聨?kù)沖突直接編譯失敗一汽,問(wèn)題找起來(lái)也很麻煩避消。還是利用resolutionStrategy,我們可以快速找到?jīng)_突的庫(kù)以及各版本號(hào)召夹,配置如下:

configurations.all {
    resolutionStrategy {
        failOnVersionConflict()
    }
}

下面是一個(gè)范例岩喷,在我的項(xiàng)目當(dāng)中,om.android.support:multidex這個(gè)庫(kù)引入了2個(gè)不同的版本:1.0.3 和 1.0.2

Conflict(s) found for the following module(s):
  - com.android.support:multidex between versions 1.0.3 and 1.0.2

找到?jīng)_突的庫(kù)及版本后戳鹅,我們可以用前面的方法均驶,強(qiáng)制指定統(tǒng)一的版本號(hào)以解決沖突。

持續(xù)更新中......

系列文章

Android Gradle學(xué)習(xí)(一):Gradle基礎(chǔ)入門
Android Gradle學(xué)習(xí)(二):如何創(chuàng)建Task
Android Gradle學(xué)習(xí)(三):Task進(jìn)階學(xué)習(xí)
Android Gradle學(xué)習(xí)(四):Project詳解
Android Gradle學(xué)習(xí)(五):Extension詳解
Android Gradle學(xué)習(xí)(六):NamedDomainObjectContainer詳解
Android Gradle學(xué)習(xí)(七):Gradle構(gòu)建生命周期
Android Gradle學(xué)習(xí)(八):統(tǒng)計(jì)Task執(zhí)行時(shí)長(zhǎng)
Android Gradle學(xué)習(xí)(九):一些有用的小技巧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末枫虏,一起剝皮案震驚了整個(gè)濱河市妇穴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隶债,老刑警劉巖腾它,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異死讹,居然都是意外死亡瞒滴,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門赞警,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妓忍,“玉大人,你說(shuō)我怎么就攤上這事愧旦∈榔剩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵笤虫,是天一觀的道長(zhǎng)旁瘫。 經(jīng)常有香客問(wèn)我祖凫,道長(zhǎng),這世上最難降的妖魔是什么酬凳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任惠况,我火速辦了婚禮,結(jié)果婚禮上宁仔,老公的妹妹穿的比我還像新娘稠屠。我一直安慰自己,他們只是感情好台诗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布完箩。 她就那樣靜靜地躺著赐俗,像睡著了一般拉队。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阻逮,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天粱快,我揣著相機(jī)與錄音,去河邊找鬼叔扼。 笑死事哭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓜富。 我是一名探鬼主播鳍咱,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼与柑!你這毒婦竟也來(lái)了谤辜?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤价捧,失蹤者是張志新(化名)和其女友劉穎丑念,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體结蟋,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脯倚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嵌屎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片推正。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宝惰,靈堂內(nèi)的尸體忽然破棺而出植榕,到底是詐尸還是另有隱情,我是刑警寧澤掌测,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布内贮,位于F島的核電站产园,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夜郁。R本人自食惡果不足惜什燕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望竞端。 院中可真熱鬧屎即,春花似錦、人聲如沸事富。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)统台。三九已至雕擂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贱勃,已是汗流浹背井赌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贵扰,地道東北人仇穗。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像戚绕,于是被迫代替她去往敵國(guó)和親纹坐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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