隨着移動端快產品速迭代,多人合做已成爲一種標杆,若是是傳統的項目都放在一個module中代碼耦合嚴重,存在各類各樣的詬病,因此組件化愈來愈盛行。下面咱們一步步揭開組件化的神祕面紗。android
基礎庫裏面有業務組件都會用到的功能好比:基礎類、glide、retrofit等,有些組價用到,有些用不到的工具模塊,單獨抽成工具模塊好比libutil,libshare,可被組件按需依賴。git
按項目業務抽取module和工具模塊,爲了方便管理,抽取config.gradle作版本統一管理,util.gradle作工具模塊依賴......github
在gradle.properties中聲明isBuildModule,isBuildModule 爲 true 時可使每一個組件獨立運行, false 則能夠將全部組件集成到宿主 App 中,編寫業務module.gradle,每一個業務組件必須依賴這個。bash
單獨編譯須要新建alone文件夾放入AndroidManifest.xml標識啓動入口,關於源碼控制和isBuildModule 切換詳見module.gradle配置markdown
if (isBuildModule.toBoolean()) { apply plugin: 'com.android.application' configSigning project } else { apply plugin: 'com.android.library' } sourceSets { main { if (isBuildModule.toBoolean()) { //獨立運行 manifest.srcFile 'src/main/alone/AndroidManifest.xml' } else { //合併到宿主 manifest.srcFile 'src/main/AndroidManifest.xml' resources { //正式版本時,排除alone文件夾下全部調試文件 exclude 'src/main/alone/*' } } } } 複製代碼
之前的項目第三方的初始化全在 項目的application中作的,如今組件化須要單一職責,不一樣的三方庫的初始化放到不一樣的業務模塊,具體步驟以下:app
1.新建module模塊:providerservice (做爲組件通訊和application業務分發),業務模塊需依賴它進行通訊mvvm
2.新建interface IApp ,代理生命App週期maven
interface IApp {
fun attachBaseContext(base: Context)
fun onCreate(base: Context)
fun onTerminate(base: Context)
}
複製代碼
3.不一樣的業務模塊實現IApp,並在對應AndroidManifest.xml註冊ide
class LoginApp: IApp { override fun attachBaseContext(base: Context) { } override fun onCreate(base: Context) { //初始化一鍵登陸,第三方庫啥的 } override fun onTerminate(base: Context) { //釋放一些資源 } } <meta-data android:name="com.ikang.loginmodule.LoginApp" android:value="ConfigAppLife" /> 複製代碼
4.編寫CommonManifestParser解析全部的ConfigAppLife到集合中,再編寫代理類AppDelegate,代理全部模塊的生命週期函數調用,最後在BaseApp相應調用。函數
// CommonManifestParser val appInfo =context.packageManager.getApplicationInfo( context.packageName, PackageManager.GET_META_DATA) if (appInfo.metaData != null) { for (key in appInfo.metaData.keySet()) { if (MODULE_VALUE == appInfo.metaData[key]) { modules.add(parseModule(key)) } } } // BaseApp override fun onTerminate() { super.onTerminate() mAppDelegate.onTerminate(this) } 複製代碼
①採用原始方式
一、providerservice模塊中在聲明接口IService,而後在聲明登錄模塊暴露的功能有哪些
interface ILoginService : IService {
val accountId: String
}
複製代碼
二、在登錄模塊loginmodule實現ILoginService
class LoginServiceImpl : ILoginService { override val accountId: String = "張三" } 複製代碼
三、在loginApp傳入實現
class LoginApp: IApp {
override fun onCreate(base: Context) {
//傳統方式通訊
LoginServiceControl.accountService = LoginServiceImpl()
}
......
複製代碼
4.如今便可在mymodule模塊MeFragment中獲取登錄模塊的用戶Id
LoginServiceControl.accountService.accountId
複製代碼
②採用arouter通訊跟上面的相似,只不過arouter是編譯期apt自動生成代碼,放入到路由表map中的,而後掃描全部的dex中的指定報名的IProvider實現的
一、providerservice模塊中在聲明接口ILoginService ,而後在聲明登錄模塊暴露的功能有哪些
interface ILoginService :IProvider {
val accountId: String
}
複製代碼
@Route(path = ProviderPath.Provider.LOGIN) class LoginServiceRouter : ILoginService { override val accountId: String = "張三" ....... } 複製代碼
3.如今便可在mymodule模塊MeFragment中獲取登錄模塊的用戶Id
@Autowired
@JvmField var loginService: ILoginService? = null
複製代碼
③基於事件總線
使用 LoacaBroadcastManage或者RxBus進行通訊
實體類放在自己的 module 中是沒法傳遞的,能夠下沉,放到業務模塊下邊的providerservice中,或者在抽取一個datamodule類
權限管理咱們將 normal 級別的權限申請都放到 Base module 中,而後在各個 module 中分別申請 dangerous 的權限 。 這樣分配的好處在於當添加或移除單一模塊時,隱私權限申請也 會跟隨移除 ,能作到最大程度的權限解禍 。不要將權限所有轉交到每一個 module 中,包括普通權限的聲明 ,由於這樣會增長 AndroidManifest的合併檢測的耗時’。
組件化資源衝突
//一、AndroidMainfest 衝突問題 AndroidMainfest 中引用了 Application 的 app:nam巳 屬性 ,當出現衝 突 時, 須要使 用 tools:replace=」android:name」來聲明 Application 是可被替換 的 。 //二、依賴jar包衝突 當包衝突出現時,能夠先檢查依賴報告,使用命令 gradledependencies查看依賴目錄樹 //三、防止資源重複,resourcePrefix 這個值只能 限定 XML 中的資源,井不能限定圖片資源,全部圖片資源仍然須要手動去修改資源名 。 android { resourcePrefix "紐件名」 } //組件化混淆,每一個module獨有的引用庫混淆放到各自 的 proguard-rule.pro 中 。 defaultConfig { ...... consumerProguardFiles 'proguard-rules.pro' } 複製代碼
多模塊能夠採用 git submodule\git subtree,或者上傳到 公司私服maven上統一管理。