每當(dāng)開始做一個(gè)新的APP , 都是喜憂參半 。喜得是對(duì)新的APP充滿期待,希望小成就感。憂的是沒有一款好的開發(fā)框架 ,最后發(fā)展成傳說中“爛尾樓” 。今兒個(gè)看到一片博客感覺寫的思路清晰,言簡意賅,很實(shí)用,特來做一下記錄 。大部分摘自原文章 。
感謝原創(chuàng)作者?https://blog.csdn.net/guiying712/article/details/55213884?;
一、為什么要組件化? ,對(duì)比一下兩張圖來說

圖一展示沒有組件化的架構(gòu) ,全部業(yè)務(wù)包都寫在主工程App中 ,業(yè)務(wù)包之間通過文件夾來區(qū)分 ,隨著業(yè)務(wù)包越來越多 ,暴露問題也會(huì)越來越多 ,業(yè)務(wù)包你中有我,我中有你 耦合性高,編譯耗
1、實(shí)際業(yè)務(wù)變化非???,但是單一工程的業(yè)務(wù)模塊耦合度太高,牽一發(fā)而動(dòng)全身;?
2、對(duì)工程所做的任何修改都必須要編譯整個(gè)工程;
3、功能測試和系統(tǒng)測試每次都要進(jìn)行;
4、團(tuán)隊(duì)協(xié)同開發(fā)存在較多的沖突.不得不花費(fèi)更多的時(shí)間去溝通和協(xié)調(diào),并且在開發(fā)過程中,任何一位成員沒辦法專注于自己的功能點(diǎn),影響開發(fā)效率;
5、不能靈活的對(duì)業(yè)務(wù)模塊進(jìn)行配置和組裝;
為了滿足各個(gè)業(yè)務(wù)模塊的迭代而彼此不受影響,更好的解決上面這種讓人頭疼的依賴關(guān)系,就需要整改App的架構(gòu)。

上圖是組件化工程模型,為方便理解這張架構(gòu)圖,下面列舉一些組件化工程中用到的名詞的含義:

總的來說 ,App的組件化是告別結(jié)構(gòu)臃腫,降低耦合 ,讓業(yè)務(wù)模塊變成獨(dú)立開發(fā)模塊 。如果要分離可以隨時(shí)打成"arr"包依賴到app殼下邊 。在集成模式下,這些業(yè)務(wù)模塊是library 。開發(fā)的時(shí)候(組件模式下)變成application,這個(gè)在gradle.builder配置文件下通過變量來控制 。
二、具體方案: 組件模式和集成模式的轉(zhuǎn)換
Android Studio中的Module主要有兩種屬性,分別為:
1、application屬性,可以獨(dú)立運(yùn)行的Android程序,也就是我們的APP;(集成模式下)

2.library屬性,不可以獨(dú)立運(yùn)行,一般是Android程序依賴的庫文件;(組件開發(fā)模式下)

不能每次集成和組件開發(fā)區(qū)手動(dòng)更改applicaton和library吧 ,要一處改變,處處生效 ,設(shè)置java靜態(tài)變量不正好可以實(shí)現(xiàn)嘛。每當(dāng)生成一個(gè)項(xiàng)目 ,androidstudio的根目錄會(huì)自動(dòng)生成gradle.properties文件 ,而項(xiàng)目中不管是moudle還是app殼任何一個(gè)build.gradle都可以去讀取gradle.properties中配置的常量? ?,gradle.properties只能定義字符串類型 。設(shè)置如下

在moudle中設(shè)置如下 : 字符串轉(zhuǎn)boolean

這樣就解決了獨(dú)立開發(fā)和集成的問題 。
三、集成模式和組件模式下的??AndroidManifest.xml的合并問題
因?yàn)樵诮M件模式下開發(fā) ,每一個(gè)moudle配置著自己的注冊(cè)清單文件 ,導(dǎo)致各自有各自的啟動(dòng)Activity ,等等一些配置,這樣在集成模式的時(shí)候,各模塊之間會(huì)起沖突,手動(dòng)改太麻煩 。其實(shí)注冊(cè)清單文件是可以指定文件夾的 ,如下圖


這樣就解決了這個(gè)問題 。
四、全局Application問題
每一個(gè)模塊可能或多或少都會(huì)用到Application全局變量 ,如果每一個(gè)模塊都去創(chuàng)建Appication ,那么在集成模式的時(shí)候就會(huì)起沖突(不允許出現(xiàn)多個(gè)Application) ,怎么解決呢,這就涉及到一個(gè)公用的模塊Common組件,在這個(gè)模塊中可以封裝2個(gè)以上模塊都用到的base類,其中就包括BaseApplication 類? ? 。Common組件顧名思義就是公用的模塊。所以每一個(gè)業(yè)務(wù)模塊都要去依賴Common組件 ,在App啟動(dòng)時(shí)候,BaseApplication會(huì)被初始化 。另外也可以初始化一些第三方庫。在組件話開發(fā)模式下會(huì)涉及到需要保存登陸返回的token,否則后續(xù)模塊接口無法請(qǐng)求。這樣就可以在Application中模擬寫登陸接口在跳轉(zhuǎn)到各自模塊。
五、Library的依賴問題
假如A組件依賴了Conmon ,和多媒體第三方組件 ,而Common和多媒體組件都依賴了日志組件 ,那么問題來了,日志組件會(huì)被重復(fù)依賴嗎,答案是不會(huì) ,在build文件下可以看到,編譯打包的時(shí)候,這些組件都被打包成了arr包 ,然后被殼工程依賴 ,在構(gòu)建過程中Gradle會(huì)自動(dòng)派出重復(fù)的組件arr包。另外常見的第三方庫中可能存在v4,v7這種包,而我們的common中也會(huì)存在這種包導(dǎo)致多包重復(fù)加載 ,解決辦法 踢除重復(fù)的包 ,例如踢除V4包

六、組件之間的調(diào)用和通信
這里我將介紹開源庫的“ARouter”?,有興趣的同學(xué)情直接去ARouter的Github主頁學(xué)習(xí):ARouter,樓主需要再總結(jié)一下,這里先不多說了 。
如果組件之間需要傳遞消息,可以通過廣播的形式 ,也可以通過Eventbus來實(shí)現(xiàn)。? ?待補(bǔ)充
七、組件之間的資源文件名字沖突
這種情況不可避免,目前沒有什么好的方法,只能說大家做好協(xié)商,后續(xù)友好的方法會(huì)補(bǔ)上 。當(dāng)然如果在組件的build.gradle添加如下的代碼:

但是設(shè)置了這個(gè)屬性后有個(gè)問題,所有的資源名必須以指定的字符串做前綴,否則會(huì)報(bào)錯(cuò),而且resourcePrefix這個(gè)值只能限定xml里面的資源,并不能限定圖片資源
八、簡介App殼的配置


主要就是release和debug中的配置? ?,mimsdk和targetsdk版本的配置統(tǒng)一 。dependencies中配置isMoudle變量組件開發(fā)模式下和集成模式下的依賴項(xiàng)。
九、總結(jié)一下業(yè)務(wù)組件和Main組件之間 。
業(yè)務(wù)組件就是根據(jù)業(yè)務(wù)邏輯的不同拆分出來的組件,業(yè)務(wù)組件的特征如下:
1、業(yè)務(wù)組件中要有兩張AndroidManifest.xml,分別對(duì)應(yīng)組件開發(fā)模式和集成開發(fā)模式,這兩張表的區(qū)別請(qǐng)查看 組件之間AndroidManifest合并問題 小節(jié)。? ? 查看第三小節(jié)
2、業(yè)務(wù)組件在集成模式下是不能有自己的Application的,但在組件開發(fā)模式下又必須實(shí)現(xiàn)自己的Application并且要繼承自Common組件的BaseApplication,并且這個(gè)Application不能被業(yè)務(wù)組件中的代碼引用,因?yàn)樗墓δ芫褪菫榱耸箻I(yè)務(wù)組件從BaseApplication中獲取的全局Context生效,還有初始化數(shù)據(jù)之用。? ? ?查看第四小節(jié)
3、業(yè)務(wù)組件有debug文件夾,這個(gè)文件夾在集成模式下會(huì)從業(yè)務(wù)組件的代碼中排除掉,所以debug文件夾中的類不能被業(yè)務(wù)組件強(qiáng)引用,例如組件模式下的 Application 就是置于這個(gè)文件夾中,還有組件模式下開發(fā)給目標(biāo) Activity 傳遞參數(shù)的用的 launch Activity 也應(yīng)該置于 debug 文件夾中;? ? 查看下圖12
4、業(yè)務(wù)組件必須在自己的 Java文件夾中創(chuàng)建業(yè)務(wù)組件聲明類,以使 app殼工程 中的 應(yīng)用Application能夠引用,實(shí)現(xiàn)組件跳轉(zhuǎn),具體請(qǐng)查看 組件之間調(diào)用和通信 小節(jié);? ? ?查看 ARouter路由的使用
5、業(yè)務(wù)組件必須在自己的 build.gradle 中根據(jù) isModule 值的不同改變自己的屬性,在組件模式下是:com.android.application,而在集成模式下com.android.library;同時(shí)還需要在build.gradle配置資源文件,如 指定不同開發(fā)模式下的AndroidManifest.xml文件路徑,排除debug文件夾等;業(yè)務(wù)組件還必須在dependencies中依賴Common組件,并且引入ActivityRouter的注解處理器annotationProcessor,以及依賴其他用到的功能組件。查看第二小節(jié)
下邊是業(yè)務(wù)組件的配置? ?,在sourceSet中過濾掉集成模式下所有debug文件 ,主要是在組件開發(fā)模式下,要設(shè)置當(dāng)前的組件Application和lunchActivity在debug文件夾下? ,繼承Common組件下的Application ,實(shí)現(xiàn)調(diào)用全局的Context .如上邊3所說

debug目錄如下圖 :

十、組件化項(xiàng)目的混淆方案
組件化項(xiàng)目的Java代碼混淆方案采用在集成模式下集中在app殼工程中混淆,各個(gè)業(yè)務(wù)組件不配置混淆文件。集成開發(fā)模式下在app殼工程中build.gradle文件的release構(gòu)建類型中開啟混淆屬性,其他buildTypes配置方案跟普通項(xiàng)目保持一致,Java混淆配置文件也放置在app殼工程中,各個(gè)業(yè)務(wù)組件的混淆配置規(guī)則都應(yīng)該在app殼工程中的混淆配置文件中添加和修改。
之所以不采用在每個(gè)業(yè)務(wù)組件中開啟混淆的方案,是因?yàn)?組件在集成模式下都被 Gradle 構(gòu)建成了 release 類型的arr包,一旦業(yè)務(wù)組件的代碼被混淆,而這時(shí)候代碼中又出現(xiàn)了bug,將很難根據(jù)日志找出導(dǎo)致bug的原因;另外每個(gè)業(yè)務(wù)組件中都保留一份混淆配置文件非常不便于修改和管理,這也是不推薦在業(yè)務(wù)組件的 build.gradle 文件中配置 buildTypes (構(gòu)建類型)的原因。
十一、組件化工程的gradle.properties文件
在組件化實(shí)施流程中我們了解到gradle.properties有兩個(gè)屬性對(duì)我們非常有用:
1、在Android項(xiàng)目中的任何一個(gè)build.gradle文件中都可以把gradle.properties中的常量讀取出來,不管這個(gè)build.gradle是組件的還是整個(gè)項(xiàng)目工程的build.gradle;
2、gradle.properties中的數(shù)據(jù)類型都是String類型,使用其他數(shù)據(jù)類型需要自行轉(zhuǎn)換;
為了解決上面問題就必須將Android項(xiàng)目中 build.gradle 中的 buildToolsVersion 和 GradleBuildTools 版本號(hào)從線上代碼隔離出來,保證線上代碼的 buildToolsVersion 和 Gradle Build Tools 版本號(hào)不會(huì)被人為改變。
AndroidStudio本地化配置gradle的buildToolsVersion和gradleBuildTools
后續(xù)補(bǔ)充demo 。
總結(jié)? :知識(shí)無價(jià) ,再次感謝原創(chuàng)作者。
組件化相比于單一工程優(yōu)勢是顯而易見的:
1.組件模式下可以加快編譯速度,提高開發(fā)效率;
2.自由選擇開發(fā)框架(MVC /MVP / MVVM /);
3.方便做單元測試;? 待補(bǔ)充
4.代碼架構(gòu)更加清晰,降低項(xiàng)目的維護(hù)難度;
5.適合于團(tuán)隊(duì)開發(fā);