前提
之前在一直單獨干,自己隨便搭個框架就開始開發(fā),such as mvc mvp mvvm clean 一些mv*架構(gòu)吧,可以隨便弄隨便改,方便自己的開發(fā)同時也可以鍛煉自己的架構(gòu)方面的知識吧,確實學(xué)到很多,比如MVP + RxJava + Retrofit + Dagger2 + GreenDAO + Glide 這些結(jié)合起來用真的讓開發(fā)速度提升了很多有想學(xué)習(xí)的同學(xué)可以看看這個app喜歡的可以關(guān)注下 Life APP
但是目前由于工作原因嗎,需要和幾個小伙伴一起開發(fā),合作開發(fā),可能不能這樣隨便玩玩了,就需要考慮到合作開發(fā)需要注意的問題,由于項目是剛剛開始,必定要考慮到之后開發(fā)一些坑嗎,打包這個問題,做android的同學(xué),每次遇到都是很無語,項目很大的話可能打包一個需要五六分鐘,太痛苦了,這是后大家應(yīng)該會想到的是插件化開發(fā),隨時隨地的更新app內(nèi)容而不需要打包上線這些流程什么的,但是這個大部分是用于動態(tài)修復(fù)bug和更新模塊,可能會有些偏離我們要做的事情,我們要做到是 代碼耦合度降低,每個模塊完全達到 解耦,不互相牽連,這樣保證了每個人的開發(fā)效率,同時每個module之間也可以打包成相應(yīng)的apk 進行測試
原理
正常我們開發(fā)app的時候在gradle里面配置的主module都是Application,其他的都是Library,那么組件化開發(fā)會有什么區(qū)別的,其實也就是讓每個module運行起來,就是就是把pludgin改成 Application 發(fā)布的時候合并即可
架構(gòu)
不知道有些同學(xué)開過餓了嗎和滴滴打車發(fā)布的他們的app開發(fā)框架,畢竟是大公司,維護成本和開發(fā)成本都很大,他們之前在某it論壇上發(fā)布了一篇文章就是說組件化開發(fā)架構(gòu),把所有的基礎(chǔ) 所有公共的東西提取出成一個BaseSDK
然后每個module依賴這個Library

簡要
先說說組件化開發(fā)會遇到的一些問題吧
1.module與Application之間調(diào)用的問題
2.跨module的Activity 或 Fragment 之間的跳轉(zhuǎn)問題
3.AAR 或Library project 重復(fù)依賴
4.資源名沖突
下面我會一一的說明如何解決這些問題。
project 配置
組件化的基本就是通過 gradle 腳本來做的。
這時候需要組件化的業(yè)務(wù)module中需要配置
if (isDebug.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
就是說當(dāng)我們在沒發(fā)布版本之前,我們的每個module之間是相互沒有任何依賴的都可以單獨運行
isDebug這個字段可以在最外層的gradle里面配置,也可以在業(yè)務(wù) module 中放一個 gradle.properties來配置,
但是我個人感覺嗎,最好在外出gradle中配置,這樣每個module 可以用一個總開關(guān)來控制。
下面放置一個完整的module 供參考
def Dependencies = rootProject.ext
if (isDebug.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'android-apt'
android {
compileSdkVersion Dependencies.androidCompileSdkVersion
buildToolsVersion Dependencies.androidBuildToolsVersion
resourcePrefix "preview_"
defaultConfig {
if (isDebug.toBoolean()) {
applicationId "com.cuieney.preview"
}
minSdkVersion Dependencies.androidMinSdkVersion
targetSdkVersion Dependencies.androidTargetSdkVersion
versionCode Dependencies.versionCode
versionName Dependencies.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
sourceSets {
main {
if (isDebug.toBoolean()) {
manifest.srcFile 'src/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/release/AndroidManifest.xml'
}
}
}
packagingOptions {
exclude 'META-INF/rxjava.properties'
}
lintOptions {
abortOnError Dependencies.abortOnLintError
checkReleaseBuilds Dependencies.checkReleaseBuilds
ignoreWarnings Dependencies.ignoreWarnings
}
compileOptions {
sourceCompatibility Dependencies.javaVersion
targetCompatibility Dependencies.javaVersion
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
repositories {
flatDir {
dirs 'libs'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
compile (name: 'StreamingLib', ext: 'aar')
compile project(':meetvrsdk')
apt Dependencies.dataDependencies.arouter_compiler
}
可以根據(jù)自己的需求進行修改
Manifest
當(dāng)module單獨運行的時候和合并運行的時候每個需要用的manifest也是有些許不同的,一些細微的差別的,但是這個我們也是需要注意的,簡單的一句代碼在gradle重配置即可
sourceSets {
main {
if (isDebug.toBoolean()) {
manifest.srcFile 'src/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/release/AndroidManifest.xml'
}
}
}
根據(jù)我們之前全局設(shè)置的isDebug來進行切換manifest即可。main 下的 manifest 寫通用的東西,另外 2 個分別寫各自獨立的,通常 release 的 manifest 只是一個空的 application 標簽,而 debug 的會有 application 和調(diào)試用的 activity(你總得要有個啟動 activity 吧)及權(quán)限。
這里有一個小 tip,就是在 release 的 manifest 中,application 標簽下盡量不要放任何東西,只是占個位,讓上面去 merge,否則比如一個 module supportsRtl 設(shè)置為了 true,另一個 module 設(shè)置為了 false,就不得不去做 override 了。
module與Application之間調(diào)用的問題
這個問題可能每個人會有不同的寫法和解決方法,這里我提供一個簡單的解決方案。
由于我們每個module都會依賴我們的BaseSDK這個library,其實在我們的 BaseSDK中直接定義個BaseApplication即可,然而每個module都可以通過BaseApplication來調(diào)用,這樣就可以解決module與Application之間調(diào)用的問題。代碼如下,可根據(jù)自己的需求不同進行修改
public abstract class BaseApplication extends Application {
public static BaseApplication app;
public static BaseApplication getInstance() {
return app;
}
protected static boolean isDebug = true;
@Override
public void onCreate() {
super.onCreate();
app = this;
initSDK();
}
public abstract void initSDK();
}
在我們的主application中可以繼承這個類然后寫一些自己需要初始化的東西
代碼如下:
public class App extends BaseApplication {
@Override
public void initSDK() {
if (LeakCanary.isInAnalyzerProcess(this)) {
return;
}
LeakCanary.install(this);
}
}
只要把公共需求的東西定義在Base中,然而調(diào)用的時候就可以解決這些問題
跨module的Activity 或 Fragment 之間的跳轉(zhuǎn)問題
這個問題呢,解決方案有很多種 可以自己寫個router來解決跳轉(zhuǎn)之間的問題,也可以借助三方工具來完成這個操作。
自己寫router呢,只不過感覺很有些麻煩,直接上圖吧

ActivityRouter
public class ActivityRouter {
public static void startActivity(Context context, String action) {
context.startActivity(new Intent(action));
}
public static void startActivity(Context context, Class clazz) {
context.startActivity(getIntent(context, clazz));
}
public static Intent getIntent(Context context, Class clazz) {
return new Intent(context, clazz);
}
public static void startActivityForName(Context context, String name) {
try {
Class clazz = Class.forName(name);
startActivity(context, clazz);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
FragmentRouter
public class FragmentRouter {
public static Fragment getFragment(String name) {
Fragment fragment;
try {
Class fragmentClass = Class.forName(name);
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return fragment;
}
}
RouterList
public class RouterList {
public static final String PREVIEW_MAIN = "com.cuieney.preview.PreviewActivity";
}
就這些自己可以這樣使用。但是我還是推薦使用三方,因為act跳轉(zhuǎn)傳值問題,act請求fragment問題,還有許多未知的坑,所以推薦兩個三方router ARouter,
ActivityRouter,這兩個可以根據(jù)自己需求進行選擇,我用的是ActivityRouter。感覺配置起來會方便許多
ActivityRouter一些配置細節(jié)
1.ActivityRouter提供的compile可以配置在BaseSDK中,然后apt配置在需要組件化的module中
2.AndroidManifest配置呢,也是如此這個需要配置在需要組件化的module中。而不是主module中,但是如果說是release可以配置在主module中
3.其他的一些配置可以參考ActivityRouter readme
AAR 或Library project 重復(fù)依賴
解決方案各有不同,可以在dependency中根據(jù)isDebug 來判斷依賴包問題等,可以是 將 compile 改為 provided,只在最終的項目中 compile 對應(yīng)的代碼,但是這種辦法只能用于沒有資源的純代碼工程或者jar包;目前我了解的是這兩種方法 ,大家可以看看還有什么好的辦法提供解決思路
資源名沖突
這個問題解決最簡單,可以自己命名的時候相互注意一下,也可以在對于的module中的gradle配置
resourcePrefix "preview_"
設(shè)置了這個值后,你所有的資源名必須以指定的字符串做前綴,否則會報錯。
但是 resourcePrefix 這個值只能限定 xml 里面的資源,并不能限定圖片資源,所有圖片資源仍然需要你手動去修改資源名。
ending
可能前期不會考慮到后面項目逐漸增大了之后 模塊之間的耦合度,需求復(fù)雜度上升等問題,但是組件化開發(fā)的形式可以解耦,降低開發(fā)成本,提高編譯速度,為什么不用呢。何樂而不為。
開開心心上班,安安心心睡覺