組件化實施流程
1組件模式和集成模式的轉(zhuǎn)換
Android Studio中的Module主要有兩種屬性丰介,分別為:
application屬性,可以獨立運行的Android程序全谤,也就是我們的APP走触;
apply plugin: ‘com.android.application’
library屬性艺智,不可以獨立運行饿自,一般是Android程序依賴的庫文件;
apply plugin: ‘com.android.library’
如何讓組件在這兩種模式之間自動轉(zhuǎn)換?
解決辦法
第一步 在gradle.properties中定義一個常量值 isModule(是否是組件開發(fā)模式锈拨,true為是砌庄,false為否):
# 每次更改“isModule”的值后,需要點擊 "Sync Project" 按鈕
isModule=false
第二步 在業(yè)務組件的build.gradle中讀取 isModule
但是 gradle.properties 還有一個重要屬性: gradle.properties 中的數(shù)據(jù)類型都是String類型奕枢,使用其他數(shù)據(jù)類型需要自行轉(zhuǎn)換娄昆;也就是說我們讀到 isModule 是個String類型的值,而我們需要的是Boolean值缝彬,代碼如下:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
2 組件之間AndroidManifest合并問題
在 AndroidStudio 中每一個組件都會有對應的 AndroidManifest.xml稿黄,用于聲明需要的權(quán)限、Application跌造、Activity、Service族购、Broadcast等壳贪,當項目處于組件模式時,業(yè)務組件的 AndroidManifest.xml 應該具有一個 Android APP 所具有的的所有屬性寝杖,尤其是聲明 Application 和要 launch的Activity违施,但是當項目處于集成模式的時候,每一個業(yè)務組件的 AndroidManifest.xml 都要合并到“app殼工程”中瑟幕,要是每一個業(yè)務組件都有自己的 Application 和 launch的Activity磕蒲,那么合并的時候肯定會沖突,試想一個APP怎么可能會有多個 Application 和 launch 的Activity呢只盹?
解決辦法
為組件開發(fā)模式下的業(yè)務組件再創(chuàng)建一個 AndroidManifest.xml辣往,然后根據(jù)isModule指定AndroidManifest.xml的文件路徑,讓業(yè)務組件在集成模式和組件模式下使用不同的AndroidManifest.xml殖卑,這樣表單沖突的問題就可以規(guī)避了站削。
上圖是組件化項目中一個標準的業(yè)務組件目錄結(jié)構(gòu),首先我們在main文件夾下創(chuàng)建一個module文件夾用于存放組件開發(fā)模式下業(yè)務組件的 AndroidManifest.xml孵稽,而 AndroidStudio 生成的 AndroidManifest.xml 則依然保留许起,并用于集成開發(fā)模式下業(yè)務組件的表單;然后我們需要在業(yè)務組件的 build.gradle 中指定表單的路徑菩鲜,代碼如下:
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
這樣在不同的開發(fā)模式下就會讀取到不同的 AndroidManifest.xml 园细,然后我們需要修改這兩個表單的內(nèi)容以為我們不同的開發(fā)模式服務。
首先是集成開發(fā)模式下的 AndroidManifest.xml接校,前面我們說過集成模式下猛频,業(yè)務組件的表單是絕對不能擁有自己的 Application 和 launch 的 Activity的,也不能聲明APP名稱、圖標等屬性伦乔,總之a(chǎn)pp殼工程有的屬性厉亏,業(yè)務組件都不能有,下面是一份標準的集成開發(fā)模式下業(yè)務組件的 AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.guiying.girls">
<application android:theme="@style/AppTheme">
<activity
android:name=".main.GirlsActivity"
android:screenOrientation="portrait" />
<activity
android:name=".girl.GirlActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
</application>
</manifest>
我在這個表單中只聲明了應用的主題烈和,而且這個主題還是跟app殼工程中的主題是一致的爱只,都引用了common組件中的資源文件,在這里聲明主題是為了方便這個業(yè)務組件中有使用默認主題的Activity時就不用再給Activity單獨聲明theme了招刹。
然后是組件開發(fā)模式下的表單文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.guiying.girls">
<application
android:name="debug.GirlsApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/girls_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".main.GirlsActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".girl.GirlActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
</application>
</manifest>
組件模式下的業(yè)務組件表單就是一個Android項目普通的AndroidManifest.xml恬试。
3 全局Context的獲取及組件數(shù)據(jù)初始化
需求:任何一個業(yè)務組件中都要能獲取到全局的 Context,而且這個 Context 不管是在組件開發(fā)模式還是在集成開發(fā)模式都是生效的疯暑。
解決辦法:
在 組件化工程模型圖中训柴,功能組件集合中有一個 Common 組件, 這個組件中主要封裝了項目中需要的基礎功能妇拯,并且每一個業(yè)務組件都要依賴Common組件幻馁,在Common組件中我們封裝了項目中用到的各種Base類,這些基類中就有BaseApplication 類越锈。
BaseApplication 主要用于各個業(yè)務組件和app殼工程中聲明的 Application 類繼承用的仗嗦,只要各個業(yè)務組件和app殼工程中聲明的Application類繼承了 BaseApplication,當應用啟動時 BaseApplication 就會被動實例化甘凭,這樣從 BaseApplication 獲取的 Context 就會生效稀拐,也就從根本上解決了我們不能直接從各個組件獲取全局 Context 的問題;
這時候大家肯定都會有個疑問丹弱?不是說了業(yè)務組件不能有自己的 Application 嗎德撬,怎么還讓他們繼承 BaseApplication 呢?其實我前面說的是業(yè)務組件不能在集成模式下?lián)碛凶约旱?Application躲胳,但是這不代表業(yè)務組件也不能在組件開發(fā)模式下?lián)碛凶约旱腁pplication蜓洪,其實業(yè)務組件在組件開發(fā)模式下必須要有自己的 Application 類,一方面是為了讓 BaseApplication 被實例化從而獲取 Context坯苹,還有一個作用是蝠咆,業(yè)務組件自己的 Application 可以在組件開發(fā)模式下初始化一些數(shù)據(jù)。
但是北滥,實際上業(yè)務組件中的Application在最終的集成項目中是沒有什么實際作用的刚操,組件自己的 Application 僅限于在組件模式下發(fā)揮功能,因此我們需要在將項目從組件模式轉(zhuǎn)換到集成模式后將組件自己的Application剔除出我們的項目再芋;在 AndroidManifest 合并問題小節(jié)中介紹了如何在不同開發(fā)模式下讓 Gradle 識別組件表單的路徑菊霜,這個方法也同樣適用于Java代碼;
4 library依賴問題
我們在build.gradle中compile的第三方庫济赎,例如AndroidSupport庫經(jīng)常會被一些開源的控件所依賴鉴逞,而我們自己一定也會compile AndroidSupport庫 记某,這就會造成第三方包和我們自己的包存在重復加載,解決辦法就是找出那個多出來的庫构捡,并將多出來的庫給排除掉液南,而且Gradle也是支持這樣做的,分別有兩種方式:根據(jù)組件名排除或者根據(jù)包名排除勾徽,下面以排除support-v4庫為例:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") {
exclude module: 'support-v4'//根據(jù)組件名排除
exclude group: 'android.support.v4'//根據(jù)包名排除
}
}
library重復依賴的問題算是都解決了滑凉,但是我們在開發(fā)項目的時候會依賴很多開源庫,而這些庫每個組件都需要用到喘帚,要是每個組件都去依賴一遍也是很麻煩的畅姊,尤其是給這些庫升級的時候,為了方便我們統(tǒng)一管理第三方庫吹由,我們將給給整個工程提供統(tǒng)一的依賴第三方庫的入口若未,前面介紹的Common庫的作用之一就是統(tǒng)一依賴開源庫,因為其他業(yè)務組件都依賴了Common庫倾鲫,所以這些業(yè)務組件也就間接依賴了Common所依賴的開源庫粗合。
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//Android Support
compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
compile "com.android.support:design:$rootProject.supportLibraryVersion"
compile "com.android.support:percent:$rootProject.supportLibraryVersion"
//網(wǎng)絡請求相關(guān)
compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
compile "com.squareup.retrofit2:retrofit-mock:$rootProject.retrofitVersion"
compile "com.github.franmontiel:PersistentCookieJar:$rootProject.cookieVersion"
//穩(wěn)定的
compile "com.github.bumptech.glide:glide:$rootProject.glideVersion"
compile "com.orhanobut:logger:$rootProject.loggerVersion"
compile "org.greenrobot:eventbus:$rootProject.eventbusVersion"
compile "com.google.code.gson:gson:$rootProject.gsonVersion"
compile "com.github.chrisbanes:PhotoView:$rootProject.photoViewVersion"
compile "com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion"
compile "com.github.GrenderG:Toasty:$rootProject.toastyVersion"
//router
compile "com.github.mzule.activityrouter:activityrouter:$rootProject.routerVersion"
}
5 組件之間調(diào)用和通信
解決方案:
ActivityRouter
ActivityRouter支持給Activity定義 URL,這樣就可以通過 URL 跳轉(zhuǎn)到Activity乌昔,并且支持從瀏覽器以及 APP 中跳入我們的Activity舌劳,而且還支持通過 url 調(diào)用方法。
6 組件之間資源名沖突
在項目中約定資源文件命名規(guī)約玫荣,比如強制使每個資源文件的名稱以組件名開始,這個可以根據(jù)實際情況和開發(fā)人員制定規(guī)則大诸。當然了萬能的Gradle構(gòu)建工具也提供了解決方法捅厂,通過在在組件的build.gradle中添加如下的代碼:
//設置了resourcePrefix值后,所有的資源名必須以指定的字符串做前綴资柔,否則會報錯焙贷。
//但是resourcePrefix這個值只能限定xml里面的資源,并不能限定圖片資源贿堰,所有圖片資源仍然需要手動去修改資源名辙芍。
resourcePrefix "girls_"
但是設置了這個屬性后有個問題,所有的資源名必須以指定的字符串做前綴羹与,否則會報錯故硅,而且resourcePrefix這個值只能限定xml里面的資源,并不能限定圖片資源纵搁,所有圖片資源仍然需要手動去修改資源名吃衅;所以我并不推薦使用這種方法來解決資源名沖突。
組件化項目的工程類型
在組件化工程模型中主要有:app殼工程腾誉、業(yè)務組件和功能組件3種類型徘层,而業(yè)務組件中的Main組件和功能組件中的Common組件比較特殊峻呕,下面將分別介紹。
1app殼工程
app殼工程是從名稱來解釋就是一個空殼工程趣效,沒有任何的業(yè)務代碼瘦癌,也不能有Activity,但它又必須被單獨劃分成一個組件跷敬,而不能融合到其他組件中讯私,是因為它有如下幾點重要功能:
1、app殼工程中聲明了我們Android應用的 Application干花,這個 Application 必須繼承自 Common組件中的 BaseApplication)妄帘,因為只有這樣,在打包應用后才能讓BaseApplication中的Context生效池凄。
2抡驼、app殼工程的 AndroidManifest.xml 是我Android應用的根表單,應用的名稱肿仑、圖標以及是否支持備份等等屬性都是在這份表單中配置的致盟,其他組件中的表單最終在集成開發(fā)模式下都被合并到這份 AndroidManifest.xml 中。
3尤慰、app殼工程的 build.gradle 是比較特殊的馏锡,app殼不管是在集成開發(fā)模式還是組件開發(fā)模式,它的屬性始終都是:com.android.application伟端,因為最終其他的組件都要被app殼工程所依賴杯道,被打包進app殼工程中,這一點從組件化工程模型圖中就能體現(xiàn)出來责蝠,所以app殼工程是不需要單獨調(diào)試單獨開發(fā)的党巾。另外Android應用的打包簽名,以及buildTypes和defaultConfig都需要在這里配置霜医,而它的dependencies則需要根據(jù)isModule的值分別依賴不同的組件齿拂,在組件開發(fā)模式下app殼工程只需要依賴Common組件,或者為了防止報錯也可以根據(jù)實際情況依賴其他功能組件肴敛,而在集成模式下app殼工程必須依賴所有在應用Application中聲明的業(yè)務組件署海,并且不需要再依賴任何功能組件。
2 功能組件和Common組件
功能組件是為了支撐業(yè)務組件的某些功能而獨立劃分出來的組件医男,功能實質(zhì)上跟項目中引入的第三方庫是一樣的砸狞,功能組件的特征如下:
1、功能組件的 AndroidManifest.xml 是一張空表镀梭,這張表中只有功能組件的包名趾代;
2、功能組件不管是在集成開發(fā)模式下還是組件開發(fā)模式下屬性始終是: com.android.library丰辣,所以功能組件是不需要讀取 gradle.properties 中的 isModule 值的撒强;另外功能組件的 build.gradle 也無需設置 buildTypes 禽捆,只需要 dependencies 這個功能組件需要的jar包和開源庫垂券。
Common組件除了有功能組件的普遍屬性外这刷,還具有其他功能:
1、Common組件的 AndroidManifest.xml 不是一張空表暂衡,這張表中聲明了我們 Android應用用到的所有使用權(quán)限 uses-permission 和 uses-feature芽隆,放到這里是因為在組件開發(fā)模式下浊服,所有業(yè)務組件就無需在自己的 AndroidManifest.xm 聲明自己要用到的權(quán)限了。
2胚吁、Common組件的 build.gradle 需要統(tǒng)一依賴業(yè)務組件中用到的 第三方依賴庫和jar包牙躺,例如我們用到的ActivityRouter、Okhttp等等腕扶。
3孽拷、Common組件中封裝了Android應用的 Base類和網(wǎng)絡請求工具、圖片加載工具等等半抱,公用的 widget控件也應該放在Common 組件中脓恕;業(yè)務組件中都用到的數(shù)據(jù)也應放于Common組件中,例如保存到 SharedPreferences 和 DataBase 中的登陸數(shù)據(jù)窿侈;
4炼幔、Common組件的資源文件中需要放置項目公用的 Drawable、layout史简、sting乃秀、dimen、color和style 等等圆兵,另外項目中的 Activity 主題必須定義在 Common中跺讯,方便和 BaseActivity 配合保持整個Android應用的界面風格統(tǒng)一。
3 業(yè)務組件和Main組件
業(yè)務組件就是根據(jù)業(yè)務邏輯的不同拆分出來的組件衙傀,業(yè)務組件的特征如下:
1、業(yè)務組件中要有兩張AndroidManifest.xml萨咕,分別對應組件開發(fā)模式和集成開發(fā)模式统抬,這兩張表的區(qū)別請查看 組件之間AndroidManifest合并問題 小節(jié)。
2危队、業(yè)務組件在集成模式下是不能有自己的Application的聪建,但在組件開發(fā)模式下又必須實現(xiàn)自己的Application并且要繼承自Common組件的BaseApplication,并且這個Application不能被業(yè)務組件中的代碼引用茫陆,因為它的功能就是為了使業(yè)務組件從BaseApplication中獲取的全局Context生效金麸,還有初始化數(shù)據(jù)之用。
3簿盅、業(yè)務組件有debug文件夾挥下,這個文件夾在集成模式下會從業(yè)務組件的代碼中排除掉揍魂,所以debug文件夾中的類不能被業(yè)務組件強引用,例如組件模式下的 Application 就是置于這個文件夾中棚瘟,還有組件模式下開發(fā)給目標 Activity 傳遞參數(shù)的用的 launch Activity 也應該置于 debug 文件夾中现斋;
4、業(yè)務組件必須在自己的 Java文件夾中創(chuàng)建業(yè)務組件聲明類偎蘸,以使 app殼工程 中的 應用Application能夠引用庄蹋,實現(xiàn)組件跳轉(zhuǎn),具體請查看 組件之間調(diào)用和通信 小節(jié)迷雪;
5限书、業(yè)務組件必須在自己的 build.gradle 中根據(jù) isModule 值的不同改變自己的屬性,在組件模式下是:com.android.application章咧,而在集成模式下com.android.library倦西;同時還需要在build.gradle配置資源文件,如 指定不同開發(fā)模式下的AndroidManifest.xml文件路徑慧邮,排除debug文件夾等调限;業(yè)務組件還必須在dependencies中依賴Common組件,并且引入ActivityRouter的注解處理器annotationProcessor误澳,以及依賴其他用到的功能組件耻矮。
Main組件除了有業(yè)務組件的普遍屬性外,還有一項重要功能:
工程的build.gradle和gradle.properties文件
1 組件化工程的build.gradle文件
在組件化項目中因為每個組件的 build.gradle 都需要配置 compileSdkVersion忆谓、buildToolsVersion和defaultConfig 等的版本號裆装,而且每個組件都需要用到 annotationProcessor,為了能夠使組件化項目中的所有組件的 build.gradle 中的這些配置都能保持統(tǒng)一倡缠,并且也是為了方便修改版本號哨免,我們統(tǒng)一在Android工程根目錄下的build.gradle中定義這些版本號,當然為了方便管理Common組件中的第三方開源庫的版本號昙沦,最好也在這里定義這些開源庫的版本號琢唾,然后在各個組件的build.gradle中引用Android工程根目錄下的build.gradle定義的版本號,組件化工程的 build.gradle 文件代碼如下:
2 組件化工程的gradle.properties文件
在組件化實施流程中我們了解到gradle.properties有兩個屬性對我們非常有用:
1盾饮、在Android項目中的任何一個build.gradle文件中都可以把gradle.properties中的常量讀取出來采桃,不管這個build.gradle是組件的還是整個項目工程的build.gradle;
2丘损、gradle.properties中的數(shù)據(jù)類型都是String類型普办,使用其他數(shù)據(jù)類型需要自行轉(zhuǎn)換;
利用gradle.properties的屬性不僅可以解決集成開發(fā)模式和組件開發(fā)模式的轉(zhuǎn)換徘钥,而且還可以解決在多人協(xié)同開發(fā)Android項目的時候衔蹲,因為開發(fā)團隊成員的Android開發(fā)環(huán)境(開發(fā)環(huán)境指Android SDK和AndroidStudio)不一致而導致頻繁改變線上項目的build.gradle配置。
作者: Android組件化方案
來源:https://www.cnblogs.com/ldq2016/
著作權(quán)歸作者所有呈础,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處舆驶。