基于fat-aar腳本實(shí)現(xiàn)多組件分包合包方案踩過(guò)的坑

原文地址:
https://juejin.im/post/5b28672bf265da59645b031a

概述

簡(jiǎn)單介紹一下項(xiàng)目情況妇蛀,筆者做這個(gè)項(xiàng)目快兩年了蚁趁,之所以有這篇文章雅任,源于項(xiàng)目的需求,因?yàn)轫?xiàng)目除了公司內(nèi)部使用属铁,還需要抽取sdk給第三方合作公司使用粱玲,并且不同的合作方可能會(huì)對(duì)sdk作改動(dòng),A公司可能不要錄屏功能昧旨,B公司可能只要視頻播放功能,不要視頻發(fā)布拾给,如何在不侵入我們主版本業(yè)務(wù)的情況下解決這個(gè)問(wèn)題呢?

聰明的你肯定想到了兔沃,切分支唄蒋得!

image

這種方式只能解決一時(shí)之需,但是后續(xù)的主版本迭代乒疏,差異會(huì)越來(lái)越大额衙,主版本同步到SDK的效率越來(lái)越低。
所以一旦是你采用了此種方案怕吴,我個(gè)人建議你做好跑路的準(zhǔn)備窍侧!

所以去年底的時(shí)候,將組件化落地到了項(xiàng)目中转绷,將各個(gè)模塊獨(dú)立伟件,按照第三方的需要,實(shí)現(xiàn)靈活的搭配议经,這樣一來(lái)斧账,可以解耦我們的各個(gè)模塊,便于維護(hù)煞肾,也可以適應(yīng)第三方的定制需求咧织,但是今天筆者討論的并非組件化相關(guān)的內(nèi)容,與該主題相關(guān)的內(nèi)容很多扯旷,筆者今天想討論的是組件化之后踩到的一些坑拯爽,,可能這些坑你永遠(yuǎn)也不會(huì)碰到钧忽,但是既然來(lái)了,看完又何妨呢逼肯?

目前項(xiàng)目架構(gòu)如圖所示:

image

組件化已基本完成耸黑,這才邁開了第一步,如何實(shí)現(xiàn)差異化呢篮幢?

1.分別打包

將各個(gè)獨(dú)立的組件分別打包成對(duì)應(yīng)的aar大刊,提供給第三方,但是又涉及到一個(gè)問(wèn)題三椿,那就是混淆的問(wèn)題缺菌,如果直接分別提供原始的aar包葫辐,那么源代碼幾乎等于完全暴露,如果分別混淆伴郁,又會(huì)存在一個(gè)問(wèn)題耿战,公共組件中常用的工具類被混淆,上層的短視頻這些組件就會(huì)找不到對(duì)應(yīng)的類焊傅。

2.合并打包

這種方案具備良好的可行性剂陡,因?yàn)樽罱K合并的文件只有一個(gè),便于混淆狐胎,遺憾的是Android官方并沒有提供這種合并的操作鸭栖,但是發(fā)現(xiàn)github上有作者開源了一個(gè)合并腳本[fat-aar.gradle](https://github.com/adwiv/android-fat-aar),這個(gè)腳本的作用實(shí)際就是合并我們的多個(gè)組件為一個(gè)aar

合并的坑

下面筆者將用一個(gè)示例工程來(lái)演示合并的一些相關(guān)問(wèn)題握巢。
合并組件工程示例

用一張簡(jiǎn)單的圖來(lái)描述其中的依賴關(guān)系


image

最上層的是我們要生成的最終的merge.aar
他會(huì)合并直播間liveroom模塊晕鹊,合并video視頻模塊,而對(duì)應(yīng)的模塊也會(huì)依賴下層的組件暴浦,如何依賴合并呢溅话?

apply from: "../fat-aar.gradle"
embedded project(':common')
embedded project(':upload')
embedded project(':download')
embedded project(':video')
embedded project(':liveroom')

注意: 需要合并的組件,只需要在最上層的組件中使用embedded關(guān)鍵字標(biāo)記即可肉渴,并且下層所依賴的所有組件公荧,都需要標(biāo)記一次

接下來(lái)直接使用命令打包合并

cd merge
gradle clean asR

合并完成之后你以為就結(jié)束了嗎?你太年輕了M妗Q!
當(dāng)你給別人使用的時(shí)候券勺,馬上就會(huì)發(fā)現(xiàn)第一個(gè)坑:


image

出現(xiàn)這個(gè)錯(cuò)誤的原因绪钥,經(jīng)過(guò)筆者肉眼的分析(各種google,各種stackoverflow)关炼,發(fā)現(xiàn)是由gradle 的插件版本引起的

筆者工作的環(huán)境

系統(tǒng): ubuntu 16.04
gradle插件版本是2.3.3
gradle的版本是3.5

降級(jí)到gradle插件版本

classpath 'com.android.tools.build:gradle:2.2.3'

此時(shí)編譯直接報(bào)錯(cuò):

image

筆者用了一個(gè)比較笨的方法:
強(qiáng)行指定fat-aar.gradle腳本中的版本

image

終于合并完成3谈埂!儒拂!
但是不明白這兩者合并出來(lái)的aar包差異在哪里寸潦,所以我將兩個(gè)插件版本分別合并的aar包截圖觀察了一下

gradle2.3.3版本合并的aar包

image

gradle2.2.3版本合并的aar包
image

可以看到后者打包出來(lái)的aar文件,在libs目錄中有一個(gè)jar包社痛,這個(gè)jar包里存放的就是相關(guān)的R文件

所以解決上述問(wèn)題的方案:

1.降級(jí)gradle插件版本到2.2.3版本见转,并修改對(duì)應(yīng)腳本里的版本號(hào)

2.使用gradle插件版本2.2.3以上,但是需要手動(dòng)修改fat-aar.gradle插件的內(nèi)容蒜哀,使之合并相關(guān)的R文件的jar包斩箫,這個(gè)問(wèn)題大家也可以思考一下?

要知道,gradle的遠(yuǎn)程依賴功能實(shí)在是太方便了乘客,我們可以很輕易的指定相關(guān)的依賴包狐血,但是由于aar文件的特殊性,我們?cè)诮M件中包含的一下遠(yuǎn)程依賴并不會(huì)被實(shí)際的合并到aar中去易核,例如你遠(yuǎn)程依賴了okhttp或者glide等相關(guān)的庫(kù)匈织,合并aar之后,就會(huì)出現(xiàn)如下的錯(cuò)誤:

image

如何解決這個(gè)問(wèn)題呢耸成?聰明的你一定想到报亩,maven

我們完全可以把這些依賴合并發(fā)布到maven中去,于是筆者嘗試著搭建了nexus私服井氢,具體的搭建不是本文討論的重點(diǎn)弦追。

幸運(yùn)的是,fat-aar的作者給我們提供了相關(guān)的publish.gradle的腳本花竞,真的不得不說(shuō)劲件,想什么來(lái)什么啊,既然有了現(xiàn)成的輪子约急,我們就直接跑唄零远!

在最上層的merge模塊中添加依賴

apply from: '../publish.gradle'

并添加如下配置

android {
    
    ...

    libraryVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.aar')) {
                def fileName = getArtifactFileName()
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }
    }

}

def getArtifactFileName() {
    return "${POM_ARTIFACT_ID}-${VERSION_NAME}.aar"
}

接下來(lái)配置自己的nexus私服即可

maven {
     //替換自己搭建的私服
     url "http://127.0.0.1:8081/nexus/content/repositories/releases"
 }

通剛才的合并打包方式,最后發(fā)布到自己的nexus私服上


image

你以為這樣就結(jié)束了嗎厌蔽?并沒有G@薄!奴饮!

實(shí)際操作過(guò)程中纬向,筆者發(fā)現(xiàn),我們本地實(shí)際是有依賴本地第三方的aar包的戴卜,換句話說(shuō)逾条,并非所有的庫(kù)都是遠(yuǎn)程依賴,你會(huì)發(fā)現(xiàn)投剥,原來(lái)腳本居然會(huì)將本地依賴的aar文件师脂,也合并到pom.xml文件中,繼而發(fā)布到nexus私服上去了江锨,這個(gè)時(shí)候給別人遠(yuǎn)程依賴吃警,就會(huì)一直找不到相關(guān)的本地庫(kù)

image

如何解決呢?

看來(lái)偷懶是不行的了啄育,還是得改腳本汤徽,經(jīng)過(guò)筆者的觀察,發(fā)現(xiàn)在生成的pom.xml中可以過(guò)濾掉

pom.withXml {
                def dependenciesNode = asNode().appendNode('dependencies')

                depList.values().each {
                    ResolvedDependency dep ->
                        def hasGroup = dep.moduleGroup != null
                        def hasName = (dep.moduleName != null && !"unspecified".equals(dep.moduleName) && !"".equals(dep.moduleVersion))
                        def hasVersion = (dep.moduleVersion != null && !"".equals(dep.moduleVersion) && !"unspecified".equals(dep.moduleVersion))

                        if (hasGroup && hasName && hasVersion) {
                            def dependencyNode = dependenciesNode.appendNode('dependency')
                            dependencyNode.appendNode('groupId', dep.moduleGroup)
                            dependencyNode.appendNode('artifactId', dep.moduleName)
                            dependencyNode.appendNode('version', dep.moduleVersion)
                        }
                }
            }

即把版本號(hào)為空的過(guò)濾掉即可灸撰。

思考與擴(kuò)展

經(jīng)過(guò)一番折騰,好歹也是合并出來(lái)我們想要的東西,但是筆者剛剛也說(shuō)到了浮毯,公司主項(xiàng)目除了自己使用完疫,還是組合成sdk給第三方使用,第三方可能會(huì)改下首頁(yè)的布局债蓝,顏色壳鹤,等等。如何在不侵入主業(yè)務(wù)的情況下饰迹,作變更呢芳誓?其實(shí)很簡(jiǎn)單,借鑒Android中多渠道包的生成啊鸭,同名的資源放在不同的目錄
遺憾的是原生的腳本并不支持這種姿勢(shì)锹淌,我在最上層的merge模塊中使用同名的資源試圖覆蓋下層的資源,達(dá)到替換的目的赠制,并未得逞B赴凇!钟些!
沒辦法烟号,還是得改腳本,改動(dòng)的思想實(shí)際就是在腳本合并的過(guò)程中政恍,優(yōu)先記錄最上層的資源名稱汪拥,當(dāng)合并下層模塊的資源文件時(shí),直接跳過(guò)即可篙耗,改過(guò)的腳本在文章的末尾迫筑。

混淆配置

關(guān)于混淆的配置,只需要在最上層的merge模塊中配置即可

注意事項(xiàng)

1.盡量不要使用原本的腳本文件鹤树,因?yàn)樵髡咭呀?jīng)幾年未更新過(guò)铣焊,文章末尾有筆者的改動(dòng)過(guò)的腳本文件

2.各個(gè)組件的清單會(huì)合并,不需要在最上層的組件中統(tǒng)一注冊(cè)

3.本地依賴的jar包不用擔(dān)心罕伯,因?yàn)槟_本會(huì)合并到最終aar庫(kù)的lib目錄下

4.本地依賴的aar包曲伊,要記得隨著遠(yuǎn)程依賴,給第三方一起依賴追他,即第三方除了依賴我們的遠(yuǎn)程依賴坟募,還需要本地依賴我們所使用的aar文件,這也算是一個(gè)缺陷吧

5.第三方依賴的插件版本最好跟我們合并使用的gradle版本一致

小結(jié)

到目前為止邑狸,合并多組件的幾個(gè)坑基本已經(jīng)走了一遍了懈糯,其實(shí)在去年底,筆者在公司的直播項(xiàng)目中已經(jīng)將組件化落地了单雾,而后在實(shí)現(xiàn)多組件的道路上也踩了不少坑赚哗,本來(lái)這篇文章并沒有打算發(fā)布出來(lái)她紫,因?yàn)椴⒉皇撬腥硕紩?huì)碰到這類需求,但是前段時(shí)間有個(gè)朋友公司問(wèn)了我相關(guān)的問(wèn)題屿储,看他踩坑了很久贿讹,所以還是覺得發(fā)布出來(lái),至少對(duì)于看到的人而言够掠,以后碰到類似問(wèn)題民褂,可以少走些彎路,提高效率疯潭。

紙上得來(lái)終覺淺赊堪,絕知此事要躬行!

示例項(xiàng)目

腳本地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竖哩,一起剝皮案震驚了整個(gè)濱河市哭廉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌期丰,老刑警劉巖群叶,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钝荡,居然都是意外死亡街立,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門埠通,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赎离,“玉大人,你說(shuō)我怎么就攤上這事端辱×禾蓿” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵舞蔽,是天一觀的道長(zhǎng)荣病。 經(jīng)常有香客問(wèn)我,道長(zhǎng)渗柿,這世上最難降的妖魔是什么个盆? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮朵栖,結(jié)果婚禮上颊亮,老公的妹妹穿的比我還像新娘。我一直安慰自己陨溅,他們只是感情好终惑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著门扇,像睡著了一般雹有。 火紅的嫁衣襯著肌膚如雪偿渡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天件舵,我揣著相機(jī)與錄音卸察,去河邊找鬼。 笑死铅祸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的合武。 我是一名探鬼主播临梗,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稼跳!你這毒婦竟也來(lái)了盟庞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤汤善,失蹤者是張志新(化名)和其女友劉穎什猖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體红淡,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡不狮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了在旱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摇零。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖桶蝎,靈堂內(nèi)的尸體忽然破棺而出驻仅,到底是詐尸還是另有隱情,我是刑警寧澤登渣,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布噪服,位于F島的核電站,受9級(jí)特大地震影響胜茧,放射性物質(zhì)發(fā)生泄漏粘优。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一竹揍、第九天 我趴在偏房一處隱蔽的房頂上張望敬飒。 院中可真熱鬧,春花似錦芬位、人聲如沸无拗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)英染。三九已至揽惹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間四康,已是汗流浹背搪搏。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留闪金,地道東北人疯溺。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像哎垦,于是被迫代替她去往敵國(guó)和親囱嫩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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

  • 概述 簡(jiǎn)單介紹一下項(xiàng)目情況漏设,筆者做這個(gè)項(xiàng)目快兩年了墨闲,之所以有這篇文章,源于項(xiàng)目的需求郑口,因?yàn)轫?xiàng)目除了公司內(nèi)部使用鸳碧,還...
    Andy周閱讀 3,613評(píng)論 0 5
  • 說(shuō)明 本文主要介紹和Gradle關(guān)系密切、相對(duì)不容易理解的配置犬性,偏重概念介紹瞻离。部分內(nèi)容是Android特有的(例如...
    jzj1993閱讀 15,577評(píng)論 1 62
  • 原文地址: http://www.reibang.com/p/f671dd76868f[https://www....
    JessYan閱讀 44,585評(píng)論 33 205
  • Android組件化項(xiàng)目地址:Android組件化項(xiàng)目AndroidModulePattern Android組件...
    半灬邊灬天閱讀 2,915評(píng)論 4 37
  • 我的船頭沒有揚(yáng)帆 有風(fēng)沒風(fēng)的時(shí)候 都會(huì)注定我走不遠(yuǎn) 走不遠(yuǎn)的時(shí)候 我東張西望尋找真實(shí)的自己 我劃著槳 讓小船兒前行...
    彩虹雪閱讀 565評(píng)論 5 2