清量組件化方案一代目
參考得到的方案疹鳄,做了部分修改
項目地址
一. 組件化我們要實現什么:
1.各模塊可以單獨運行
2.任意模塊聯合調試:
3.代碼隔離猫妙,看上圖雏亚,不管單獨運行還是聯合調試盛卡,每個模塊只引用一個一個項目:ycbaselib
系任,,依賴通過配置文件來管理步氏,在整個開發(fā)周期中都不用compile
其他module
响禽,所以各個模塊之間看不到其他模塊的代碼,各個模塊交互通過路由協(xié)議及ycbaselib
中的module服務管理荚醒。
二.怎么用
問:怎么單獨運行模塊
答:采用此框架后芋类,如下圖所示每個模塊可以單獨運行
問:如何掛載其他模塊運行
答:掛載其他module只需要在當前module根目錄的gradle.properties里加下配置debugComponent=ycpublishlib,yccarlib
,而不需要在build.gradle
中手動添加,在編譯時會根據配置幫你添加依賴界阁,這樣就做到了各個模塊的代碼隔離梗肝。
問:每個模塊需要在Application里做初始化等一些操作,如何做到铺董?
答:在ycbaselib里定義了一個接口IApplicationLike
,定義了一些類似Application的方法,該接口定義如下:
public interface IApplicationLike {
void onCreate(Application application); //初始化
void exitApp(); //退出app
void onTrimMemory(int level); //內存等級
}
每個模塊可以寫一個實現了該接口的類精续,在對應的方法下做相應的操作坝锰。在編譯期會使用AOP的方式,在真正的Application類里插入這些代碼的調用重付。
問:依賴其他module有幾種方式
答:有兩種依賴方式顷级,compile project
或者compile aar
,根據配置确垫,假如為:debugComponent=ycpublishlib
則會以compile project
的方式添加ycpublishlib
依賴弓颈,如果是debugComponent=aar:ycpublishlib
則會以compile aar
的方式添加ycpublishlib
依賴,當然前提是你依賴的模塊要發(fā)布過aar文件删掀。
三.ycbaselib放什么
- 公共的第三方庫翔冀,注意:是所有模塊都要用到的,比如:網絡框架披泪、數據庫纤子、圖片加載、Rxjava款票,所有業(yè)務相關的第三方庫都放各自模塊控硼。
- 公共res資源:圖片、顏色等
-
服務管理艾少,各個模塊需要對外提供的服務會放此處:
image.png
此處只定義各個服務接口卡乾,具體的服務實現放在各個業(yè)務的模塊下。
ServiceHost
為服務管理商缚够,有兩個方法:獲取服務和注冊服務幔妨。
//獲取服務
public static<T> T getService(Class<T> clazz);
//注冊服務
public static<T> void addService(Class<T> clazz, T instance)潮瓶;
比如我想獲取用戶模塊的某些東西我先從ServiceHost
獲取用戶模塊的服務類:
IUserService service = ServiceHost.getService(IUserService.class);
service.getUserName();
拿到用戶服務類陶冷,就可以使用用戶模塊提供的的功能了,注意:假如當前模塊沒有掛載用戶模塊毯辅, 此處獲取到的用戶服務為空埂伦,要做好判空處理
備注:ycbaselib應該輕量,不含具體業(yè)務思恐,只放所有模塊都要用到的東西沾谜。
四.原理
假設:運行A模塊,A模塊掛載了B模塊和C模塊
- 根據編譯命令胀莹,如
ycpublishlib:assembleRelease
找到當前運行模塊也就是A模塊基跑,將A模塊設為apply:application
其他掛載模塊B、C設為apply:library
- 設置
SourceSet
描焰,每個模塊單獨運行時和作為library時可能代碼和res資源略有不同媳否,此處根據運行模塊(A)和掛載模塊(B栅螟、C)對SourceSet
做不同配置 - 根據A模塊里的配置文件(放在gradle.properties里),在編譯時添加B篱竭、C模塊依賴 力图,類似于動態(tài)在buildgradle里添加
compile project(':Bproject')
。掺逼。吃媒。 - 編譯結束后,遍歷所有的class文件吕喘,開始字節(jié)碼插入功能赘那,根據A模塊配置文件里的
Application
類名全稱,找到A模塊的Application
類氯质,然后根據根項目配置里的applikename類名的全稱募舟,找到所有實現了IApplicationLike
接口的類,然后在Application
里挨個調用IApplicationLike
對象的相關方法實現其他掛載模塊的初始化工做等病梢。
五.怎么做
配置:
1.在項目根目錄的gradle.properties里添加如下配置:
mainmodulename=app //主項目是哪個module
applikename = com.yiche.ycbaselib.component.IApplicationLike //IApplicationLike接口全名
2.在每個模塊下添加gradle.properties文件胃珍,然后添加如下配置:
isRunAlone=true
applicationName = 'com.yiche.circles.CirclesApplication' //該模塊單獨運行時配置的Application全名
debugComponent=ycpublishlib //debug依賴
compileComponent=ycpublishlib //release依賴
3.在項目根目錄build.gradle里:
buildscript {
repositories {
//...略...
jcenter()
}
dependencies {
clclasspath 'com.yiche.litecomponent:ycbuild-gradle:1.0.3'
//...略...
}
}
allprojects {
repositories {
flatDir {
dirs '../release_aars' //本地依賴aar時指定目錄
}
}
//...略...
}
4.在每個模塊的build.gradle里:
apply plugin: 'com.yiche.litecomponent'//注意這里,不再是android.application或者library之類
//...略...
5.代碼部分蜓陌,在除主模塊以外其他每個模塊main目錄下新建runalone目錄:
這個是單獨運行時使用的,可以只放置一個AndroidManifest.xml觅彰,用來配置application信息以及啟動的Activity等信息,也可以放java目錄和res目錄用于存放代碼和資源文件钮热,運行時會將runalone里的代碼和res和main目錄下的合并填抬。目錄結構如下圖所示。
[參考]以下是插件里的部分源碼隧期,展示合并SourceSet飒责,PS:AndroidManifest不能合并,單獨運行和作為library時各自用各自的
f每個模塊寫一個類仆潮,實現ycbaselib
模塊下的IApplicationLike
接口宏蛉,用于模仿Application
該接口定義如下:
public interface IApplicationLike {
void onCreate(Application application);
void exitApp();
void onTrimMemory(int level);
}
類似于Application的功能,在這里根據需求添加模塊的初始化性置、或者退出app時的操作等拾并。這里的代碼會在編譯時動態(tài)插入。
(完畢)
配置說明:
1.根目錄的gradle.properties
mainmodulename:標記哪個模塊是主項目鹏浅,一般都是app嗅义,設置這個是為了當直接輸入assembleRelease
等構建命令的時候知道哪個是主項目入口。
ps:編譯某個moudle的命令是
gradlew modulename:assembleRelease
這樣隐砸。咱們一般敲assembleRelease
相當于app:assembleRelease
applikename :IApplicationLike
是一個接口之碗,模仿Application的功能,一般放在base包下(比如本項目的ycbaselib
包下)季希。為什么要放這個全名呢褪那,因為在編譯時要動態(tài)添加代碼幽纷,會根據這個全名找到所有實現了該接口的類,然后在Application里動態(tài)插入代碼博敬。
問:如何實現模擬Application功能霹崎?
答:當編譯完成后,本框架會通過字節(jié)碼插入的方式冶忱,遍歷所有的class文件找到所有實現了IApplicationLike
接口的對象,然后在真正的Application下挨個插入調用代碼境析。
2.模塊目錄的gradle.properties
isRunAlone:一般為true囚枪,只有當本模塊需要發(fā)布library包也就是打aar包的的時候改為false。
applicationName :本模塊單獨運行時指定的Application類全名劳淆。每個模塊都必須定義一個Application链沼,因為每個模塊都可能掛載其他模塊聯合運行,其他模塊有可能需要在Application里做一些操作沛鸵。所以就算本模塊不需要使用Application也需要定義一個Application類括勺。
問:為什么需要在配置里加applicationName呢?
答:在編譯期間需要動態(tài)添加代碼曲掰,根據applicationName
找到真正的Application
類疾捍,然后再找到所有實現了IApplicationLike
接口的類,然后在Application
類的對應方法里添加所有IApplicationLike
實現類的調用代碼栏妖。
PS:applicationName
是強制需要指定的乱豆。你定義的Application可以不寫任何代碼如下圖,這樣也不影響注入代碼的:
//記得在runalone目錄下的AndroidManifest里注冊
public class CarApplication extends Application{
//我是空的
}
debugComponent吊趾、compileComponent:本模塊debug依賴以及realease依賴宛裕。用于配置聯合其他模塊調試時的依賴,會在編譯期間根據這個配置幫你引用其他項目论泛。
依賴有兩種方式揩尸,比如
debugComponent:ycuserlib,aar:yccarlib
表示依賴ycuserlib和yccarlib兩個模塊,前者是直接直接compile ycuserlib的projrct屁奏,后者是compile yccarlib發(fā)布的aar文件岩榆。當某個模塊配置isRunAlone
為false會打一個aar包并拷貝到根目錄里的release_aars
文件夾,當使用aar:ycxxlib
依賴時了袁,會到這個目錄下找對應的aar文件并添加依賴朗恳。
其他:
ycuserblib提供了一個無侵入初始化的方案,通過ContentProvider來實現载绿,原理參考使用ContentProvider初始化你的Library粥诫,可以不用在Application的onCreate里加代碼來時現模塊的初始化。
主module的不同之處:
- 主module的isRunalone永遠為true崭庸,主module不會作為library使用
- 其他模塊不能依賴主module怀浆。
- 主module不需要設置runalone目錄谊囚,它不會作為library使用,一直是application模式