淺談Gradle(二)與SourceSets

之前寫過了一篇Gradle(一)你画,那是根據(jù)別人寫的文章總結(jié)寫的,當(dāng)時(shí)其實(shí)還是很多不懂桃漾,包括我現(xiàn)在對gradle的理解也其實(shí)還是似懂非懂坏匪,但是還是要寫,每次寫完之后包括再重新多看幾次呈队,都會有新的感悟剥槐。
然后我想說的是關(guān)于Gradle的文章,其實(shí)網(wǎng)上寫得好的并不是很多宪摧,就那一兩篇寫得比較好粒竖,然后其他都是千篇一律,還是比較建議就是看官方的文檔几于,但是官方的文檔其實(shí)有時(shí)候也讀不懂他說的到底是個(gè)什么意思蕊苗,所以我這里比較推薦兩本書:《Android Gradle權(quán)威指南》和《Gradle of Android 中文版》
其實(shí)這兩本書也并不是把所有的東西都講得很清楚,但是讀之后會至少有個(gè)概念沿彭。當(dāng)然如果以前沒接觸腳本的話估計(jì)看一遍還是看不懂朽砰,包括我其實(shí)看了很多一樣的內(nèi)容,但是現(xiàn)在也還有很多不知道。

一.Gradle

相關(guān)的內(nèi)容比較多瞧柔,我就不一點(diǎn)一點(diǎn)開始講漆弄,就貼個(gè)別人寫好的文章出來,但我個(gè)人還是比較建議去看書
https://www.cnblogs.com/ut2016-progam/p/5871430.html

1.gradle

gradle是什么呢造锅,我個(gè)人簡單的理解就是他是一個(gè)構(gòu)建工具撼唾,他有個(gè)特性是約定優(yōu)于配置,他是基于Groovy的領(lǐng)域?qū)S谜Z言(DSL)哥蔚,其實(shí)這個(gè)DSL我也不懂具體是什么意思倒谷。
關(guān)于Groovy語言,其實(shí)我感覺和js還是比較相似的糙箍,是不是所有的腳本語言都一個(gè)尿性渤愁,建議還是要看一下,其他的都還好深夯,主要需要注意一下它的那個(gè)閉包的概念抖格,也就是Closure類型。

2.生命周期

比較重要的一點(diǎn)是gradle的構(gòu)建過程是有生命周期這一概念的塌西,分為三個(gè)階段:
(1)初始化階段:創(chuàng)建 Project 對象他挎,如果有多個(gè)build.gradle,也會創(chuàng)建多個(gè)project
(2)配置階段:在這個(gè)階段捡需,會執(zhí)行所有的編譯腳本办桨,同時(shí)還會創(chuàng)建project的所有的task,為后一個(gè)階段做準(zhǔn)備
(3)執(zhí)行階段:在這個(gè)階段站辉,gradle 會根據(jù)傳入的參數(shù)決定如何執(zhí)行這些task,真正action的執(zhí)行代碼就在這里

其實(shí)可以先把每一個(gè).gradle文件當(dāng)成一個(gè)Project 呢撞,初始化階段就是把.gradle變成Project對象,第二個(gè)階段就是創(chuàng)建Project對象里面的任務(wù)饰剥,我個(gè)人理解就是走.gradle文件里面的代碼(但是估計(jì)這個(gè)解釋不是很對殊霞,我對第二個(gè)階段不是很清楚),第三個(gè)階段就是執(zhí)行這些任務(wù)汰蓉。

那么什么時(shí)候開始走這個(gè)生命周期呢绷蹲,不知道,我沒有找到有哪篇文章說這個(gè)的顾孽,但是從我打印的結(jié)果來看祝钢,我認(rèn)為是只要執(zhí)行某些任務(wù)都會走這3個(gè)生命周期,比如說Rebuild或者運(yùn)行程序若厚,都會執(zhí)行生命周期拦英,比如這段Rebuild時(shí)的打印內(nèi)容


第一個(gè)部分就是執(zhí)行的任務(wù),其實(shí)在AS的工具欄點(diǎn)按鈕测秸,相當(dāng)于在命令行輸入要執(zhí)行的命令疤估,第二個(gè)部分是我在gradle文件里面寫的一些打印的操作灾常,我覺得這個(gè)就是配置階段,因?yàn)槟阈薷牧薌radle文件中的內(nèi)容铃拇,它需要重新進(jìn)行配置吧钞瀑,第三個(gè)部分前面有冒號的就是執(zhí)行任務(wù),也就是執(zhí)行階段慷荔。
所以對生命周期我是這樣認(rèn)為的仔戈,初始化階段只要setting.gradle文件沒變,它就只進(jìn)行初始化一次拧廊,如果這個(gè)文件變了,就需要重新進(jìn)行初始化晋修。然后是配置階段就是執(zhí)行項(xiàng)目Gradle和模塊gradle里面的代碼吧碾,每次執(zhí)行任務(wù)都會重新執(zhí)行配置階段吧。然后執(zhí)行階段就是打印中的最后一部分墓卦,很明顯能看出倦春,也是每次操作都會執(zhí)行這個(gè)生命周期。

其實(shí)我在開發(fā)gradle的時(shí)候遇見了一個(gè)BUG落剪,點(diǎn)擊sync now之后睁本,會先跑一遍日記,然后刷新再跑一遍忠怖,在第一遍打印的結(jié)尾會打印這個(gè)



要不是我手快都截不到圖呢堰,可以看出這時(shí)候是配置階段,而這時(shí)候還沒生成variant凡泣,所以我當(dāng)時(shí)獲取variant出現(xiàn)了為空的BUG枉疼。我感覺這個(gè)階段也是多渠道資源進(jìn)行合并的階段。

3.插件

在android中Gradle還有一個(gè)比較重要的概念就是插件鞋拟。在根目錄下的build.gradle文件骂维,也就是整個(gè)工程的build.gradle文件

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.2'
        

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

里面某塊表示什么意思,網(wǎng)上也有很多說明贺纲,因?yàn)槲也唤?jīng)常改動這個(gè)文件航闺,所以這里我就別在不懂裝懂了。

然后就是每個(gè)module的gradle文件猴誊,這個(gè)是比較常用的潦刃,一般都會這樣寫:

apply plugin: 'com.android.application'
android {
        .....
}

這個(gè)就是插件,gradle里面引用了com.android.application這個(gè)插件稠肘。這個(gè)是一個(gè)閉包福铅,如果之前看過groovy就知道,可以看到Gradle里面基本所有的地方都用到閉包的寫法项阴。android這個(gè)關(guān)鍵字傳入的閉包里面的defaultConfig啊buildTypes啊這些都是屬于這個(gè)插件的內(nèi)容滑黔,但也不一定笆包,因?yàn)檫@個(gè)插件是是擴(kuò)展了java插件,舉個(gè)栗子略荡,里面的sourceSets就是java插件的庵佣。所以要想知道里邊具體是怎么配置的,可以搜索這個(gè)插件的內(nèi)容汛兜。常用到的就大概這些
defaultConfig是基本的配置信息
buildTypes和productFlavors我在多渠道打包的文章有詳細(xì)講
sourceSets就是源集巴粪,等下會詳細(xì)去講一點(diǎn)
其他的詳細(xì)內(nèi)容也不太想多說什么,因?yàn)橐黄恼驴隙ㄊ菍懖煌晁信渲美锞唧w該詳細(xì)怎么做的粥谬,我這里暫時(shí)先打算說SourceSets

二.SourceSets

SourceSets被稱作原集合肛根,一般可以用它來指定資源的路徑。



比如我這個(gè)地方漏策,我想把兩個(gè)文件夾中的代碼和原文件夾中的進(jìn)行合并派哲,我可以這樣寫

 sourceSets{
        main{
            java {
                srcDirs "src/mtone"
                srcDirs "src/mttwo"
            }
        }
    }

可以看到這個(gè)set,學(xué)過java的都知道這是集合掺喻,其實(shí)gradle里面很多地方可以用java代碼去寫
我們打印看看這個(gè)set是什么

 sourceSets{
        main{
            java {

                srcDirs "src/mtone"
                srcDirs "src/mttwo"

                sourceSets.all{set ->
                    println "${set.name}的文件是 ${set.java.srcDirs}"
                    }
                }

            }
        }
    }

可以看到打印的結(jié)果



set的name其實(shí)就是基本和渠道差不多芭届,然后java.srcDirs就是這個(gè)set的java文件的路徑,這是一個(gè)我比較想說的點(diǎn)感耙,前面我說了指定資源路徑褂乍,java其實(shí)是其中一個(gè),我們現(xiàn)在可以來看看大概有什么資源文件




所以你可以寫一個(gè)文件夾即硼,然后在文件夾寫一些資源文件逃片,當(dāng)你某個(gè)渠道想要把這些資源文件加進(jìn)去的時(shí)候,你可以這樣寫
 渠道名{
        main{
            res{
                 srcDirs "你自己資源文件夾的路徑"
            }
        }
    }

這樣就可以在編譯時(shí)把你自己的資源文件和原項(xiàng)目的進(jìn)行合并只酥,當(dāng)然會有一定的合并規(guī)則题诵,這個(gè)我不多說,你可以百度“資源合并規(guī)則”层皱。還有一點(diǎn)是我覺得并不是在編譯時(shí)才合并的性锭,而是在配置的生命周期時(shí)執(zhí)行sourceSets里面的操作,對所有的資源進(jìn)行合并叫胖。

然后我再說一個(gè)場景

我這三個(gè)包都要進(jìn)行合并的草冈,但是出現(xiàn)了這樣的一個(gè)問題,我想很多人都碰過這個(gè)問題瓮增,沒錯(cuò)怎棱,就是重復(fù)類的問題,這時(shí)我這里的main也就是原本的目錄下有個(gè)MyTestOne.java類绷跑,但是我的mtone目錄下也有一個(gè)MyTestOne.java類拳恋,這時(shí)你就沒法合并了,這時(shí)你編譯的話會報(bào)一個(gè)錯(cuò)誤砸捏,報(bào)重復(fù)類的錯(cuò)誤谬运。

想想就知道不可能有兩個(gè)同名類共存隙赁,因?yàn)槿绻阏{(diào)用的話系統(tǒng)怎么知道你是調(diào)用了哪個(gè),所以我們的做法是必須在合并的時(shí)候去去掉其中一個(gè)MyTestOne.java梆暖。其實(shí)這里也是說我們可以在gradle中動態(tài)的去選著給項(xiàng)目指定使用哪個(gè)MyTestOne.java伞访。

有人用過gradle的話肯定知道可以使用 exclude來排除,但是如果我們直接這樣寫的話

exclude 'com/example/kylin/fristtest/MyTestOne.java'

就會把兩個(gè)MyTestOne.java都給排除轰驳,因?yàn)樗麄兊陌且粯拥暮裰溃恍拍憧梢栽囋嚒K晕覀兊淖龇ň褪且玫剿诤喜⒅笆菍儆谀膫€(gè)文件夾的级解,這時(shí)候就需要用到set的java路徑冒黑,因?yàn)檫@個(gè)是屬于java的部分

 sourceSets{
        main{
            java {

                srcDirs "src/mtone"
                srcDirs "src/mttwo"

                sourceSets.all{set ->
                    println "${set.name}的文件是 ${set.java.srcDirs}"
                    if(name == "main"){
                        Set myt = java.srcDirs;
                        println myt
                    }
                }

            }
        }
    }

我們直接這樣打印看看



可以看出我的結(jié)果這里打印出了三個(gè),這樣我們就可以拿到自己想保留的路徑下的MyTestOne.java勤哗,我們可以這樣寫

sourceSets{
        main{
            java {

                srcDirs "src/mtone"
                srcDirs "src/mttwo"

                sourceSets.all{set ->
                    println "${set.name}的文件是 ${set.java.srcDirs}"
                    if(name == "main"){
                        Set myt = java.srcDirs;
                        println myt
                        myt.each {
                            if(it.name != "mtone"){
                                exclude 'com/example/kylin/fristtest/MyTestOne.java'
                            }
                        }
                    }
                }

            }
        }
    }

拿到set之后可以遍歷薛闪,然后用name獲取具體的路徑,這樣子就可以排除指定路徑下的MyTestOne.java俺陋。

但是這里不能獲取到多渠道的路徑,比如我這樣寫



我多加了ali和baidu的渠道昙篙,這里卻獲取不了腊状,為什么?
因?yàn)檫@里看到外層



沒錯(cuò)已經(jīng)是指定到main的苔可,如果我們想在ali的渠道下弄缴挖,我們需要再寫個(gè)ali的閉包

我們這樣寫,把引入的資源放到ali中焚辅,可以看到結(jié)果


可以看出這里有個(gè)很奇怪的問題映屋,沒錯(cuò),就是多渠道的文件同蜻,可以不用指定srcDirs棚点,他會自動合并,但是自動合并情況下你用set是無法獲取到其他渠道的文件湾蔓,set只能獲取在閉包內(nèi)srcDirs定義的文件瘫析。我覺得這個(gè)原因是因?yàn)槟闶菑纳系较聢?zhí)行時(shí)打印的,這時(shí)候還沒有合并默责,等你的gradle里面寫的代碼執(zhí)行完之后贬循,才開始進(jìn)行合并操作,所以打印的時(shí)候還沒開始進(jìn)行合并桃序。

那怎么辦杖虾,我還想獲取其它渠道的文件的話該怎么辦,有兩個(gè)辦法媒熊,第一個(gè)就是在main中用srcDirs指定渠道的文件奇适,我覺得AS默認(rèn)合并的操作也是指定srcDirs坟比,但是我沒試過這種方法,不知道是否可行滤愕。
第二種方法就是用File温算,沒錯(cuò),我之前說過gradle中可以寫java的代碼间影,那我其實(shí)也可以使用java中的File類來操作文件注竿。
比如說我想獲取到src文件夾下的所有文件,我可以這樣寫魂贬,然后順便打印看看

File file = file('src')
File[] tempList = file.listFiles()
println "所有文件夾" + tempList

可以看到確實(shí)能打印出來巩割,然后你想怎么做,按照java操作File的方式去做就行了付燥。

從這個(gè)打印還可以看到一個(gè)很有意思的地方宣谈,就是他和SourceSets內(nèi)部打印的順序是穿插的,我也不知道為什么會這樣键科。

好了闻丑,我暫時(shí)就只說這么多,還想看詳細(xì)的SourceSets的操作勋颖,可以去看官網(wǎng)的 API 嗦嗡,而如果你想做某些操作而API沒有的話,你可以考慮一下用java能不能實(shí)現(xiàn)你想要的功能饭玲。

還有就是Gradle的內(nèi)容太多了侥祭,而網(wǎng)上很多人講得都比較淺,上面對SourceSets的操作是我自己在實(shí)踐中去不斷踩坑才總結(jié)出來的茄厘。所以我只能說Gradle太難了矮冬,閉包的思想,還有原理次哈,不同的插件還有不同的操作胎署,而且你在開發(fā)時(shí)報(bào)錯(cuò)的話,查找錯(cuò)誤信息還要帶點(diǎn)推理的思路去找出錯(cuò)誤在哪窑滞,說不定你每次運(yùn)行都會產(chǎn)生不同的錯(cuò)誤硝拧。最主要是沒有找到那種比較去完整理解的教程,所以寫這個(gè)東西相關(guān)的還是挺難的葛假,首先自己就不是很懂障陶,然后還不知道要怎么去組織語言,我這也只能碰到什么寫什么了聊训。要是我把這個(gè)東西弄懂個(gè)七八十抱究,我也不專門寫文章,直接寫書得了带斑。
我想說的是鼓寺,如過我對SourceSets的操作能幫到你勋拟,那當(dāng)然是好,如果幫不到你妈候,我也沒辦法敢靡,它的內(nèi)容還是比較多的,我現(xiàn)在肯定也沒法全懂苦银,這東西也沒人教我啸胧,我去踩坑,能寫的我都寫了幔虏,有些坑我沒踩過我也不懂怎么處理纺念。

這篇是補(bǔ)上周的,寫gradle組織語言有點(diǎn)難想括,所以上周沒能出一篇

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陷谱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瑟蜈,更是在濱河造成了極大的恐慌烟逊,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铺根,死亡現(xiàn)場離奇詭異宪躯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)夷都,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來予颤,“玉大人囤官,你說我怎么就攤上這事「蚺埃” “怎么了党饮?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驳庭。 經(jīng)常有香客問我刑顺,道長,這世上最難降的妖魔是什么饲常? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任蹲堂,我火速辦了婚禮,結(jié)果婚禮上贝淤,老公的妹妹穿的比我還像新娘柒竞。我一直安慰自己,他們只是感情好播聪,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布朽基。 她就那樣靜靜地躺著布隔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稼虎。 梳的紋絲不亂的頭發(fā)上衅檀,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天,我揣著相機(jī)與錄音霎俩,去河邊找鬼哀军。 笑死,一個(gè)胖子當(dāng)著我的面吹牛茸苇,可吹牛的內(nèi)容都是我干的排苍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼学密,長吁一口氣:“原來是場噩夢啊……” “哼淘衙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腻暮,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤彤守,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后哭靖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體具垫,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年试幽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筝蚕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铺坞,死狀恐怖起宽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情济榨,我是刑警寧澤坯沪,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站擒滑,受9級特大地震影響腐晾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丐一,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一藻糖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧库车,春花似錦颖御、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疹鳄。三九已至,卻和暖如春芦岂,著一層夾襖步出監(jiān)牢的瞬間瘪弓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工禽最, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留腺怯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓川无,卻偏偏與公主長得像呛占,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子懦趋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,302評論 25 707
  • Android Studio正式版早已經(jīng)發(fā)布了晾虑,默認(rèn)使用Gradle構(gòu)建,GitHub上80%的Android項(xiàng)目...
    流哲羽閱讀 2,881評論 1 13
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理仅叫,服務(wù)發(fā)現(xiàn)帜篇,斷路器,智...
    卡卡羅2017閱讀 134,702評論 18 139
  • 蛋殼的用處實(shí)驗(yàn)小學(xué)206班 同2018年4月1日 早上诫咱,小蟲子笙隙、小蝴蝶和小螞蟻用半個(gè)蛋殼搭了一個(gè)蹺蹺板。 玩著...
    梟島閱讀 584評論 1 1
  • 大家好坎缭,今天要聊的是中西方的法律守護(hù)神
    杰瑞喵閱讀 1,013評論 0 1