Android組件化開發(fā)實(shí)踐(三):組件開發(fā)規(guī)范

不以規(guī)矩,不成方圓。特別是多人協(xié)作開發(fā)時(shí),如果沒有統(tǒng)一的開發(fā)規(guī)范,勢(shì)必會(huì)造成各種混亂。在實(shí)際開發(fā)中,常常會(huì)碰到的問題有:

  • 引入的某個(gè)第三方庫(kù)版本沖突;
  • 不同組件里同名資源文件被覆蓋;
  • APP殼工程打包時(shí)AndroidManifest.xml合并發(fā)生錯(cuò)誤;

往往單獨(dú)的組件工程運(yùn)行良好,但是集成到殼工程時(shí)就是不行,所以我們必須要嚴(yán)格遵守規(guī)范,盡可能減少這種問題的出現(xiàn)。以下是我在實(shí)際開發(fā)中采用的一些步驟規(guī)范:

1. 新建組件工程

我的每個(gè)組件都是一個(gè)單獨(dú)的小工程,而不是像其他的方案那樣,只有一個(gè)主工程,每個(gè)組件只是工程里的一個(gè)module,這種方式實(shí)質(zhì)上還是單一工程模式。這樣在代碼權(quán)限管控,組件職責(zé)劃分上就很明確了,每個(gè)工程是一個(gè)組件,每個(gè)組件有一個(gè)owner(也就是負(fù)責(zé)人)。

打開Android Studio(目前只采用該IDE來(lái)開發(fā),其他IDE不考慮),點(diǎn)擊"File -> New -> New Project...",全新創(chuàng)建一個(gè)新的工程,工程名字以及包名根據(jù)實(shí)際業(yè)務(wù)來(lái)定。

2. 新建module

在剛創(chuàng)建好的工程中,點(diǎn)擊"File -> New -> New Module... -> Android Library",創(chuàng)建一個(gè)新的library module,接下來(lái)我們所有的組件業(yè)務(wù)代碼都將在該module下面開發(fā)。

如圖所示,我們所有的組件工程都包含2個(gè)module,一個(gè)是app,一個(gè)是library。在library里開發(fā)真正的業(yè)務(wù)功能,在app里只是一個(gè)組件的入口,或者是一些demo測(cè)試代碼。

library module的包名設(shè)置規(guī)則:應(yīng)用包名+ "." + 業(yè)務(wù)模塊名,假設(shè)你的應(yīng)用包名為com.ali.app,你要開發(fā)的業(yè)務(wù)組件為用戶個(gè)人中心,則你的包名可定義為:com.ali.app.userinfo。注意不要與應(yīng)用以及其他業(yè)務(wù)組件的包名發(fā)生沖突,如果你的團(tuán)隊(duì)足夠大,甚至是跨業(yè)務(wù)部門,則組件包名的命名需要格外慎重,你可以加上你部門的代號(hào),這樣別人在使用該組件時(shí),一眼就能知道該組件是誰(shuí)誰(shuí)誰(shuí)開發(fā)的。

3. 資源名命名規(guī)則

所有資源文件的命名都需要以業(yè)務(wù)模塊名為前綴,注意不要與其他業(yè)務(wù)模塊前綴名沖突。假設(shè)我們?cè)陂_發(fā)"登錄"相關(guān)的業(yè)務(wù),業(yè)務(wù)模塊名為"login",則相關(guān)資源文件命名例子:

  • layout文件:login_activity_quicklogin.xml、login_activity_register.xml
  • anim文件:login_slide_in.xml
  • mipmap文件:login_btn_submit.png
  • string:<string name="login_submit">提交</string>

包括但不限于以上這些資源文件,所有資源文件的命名都必須遵循該規(guī)則,否則可能在集成的時(shí)候會(huì)被沖突掉。當(dāng)然還有一種方式是在build.gradle文件添加如下配置:

resourcePrefix "module_login"

這個(gè)在打包編譯時(shí)會(huì)自動(dòng)為所有資源加上前綴,但是不管加不加該配置,還是強(qiáng)烈建議資源命名增加前綴。

4. 第三方庫(kù)依賴

在我們使用第三方依賴庫(kù)時(shí),需要特別注意依賴庫(kù)的版本號(hào)。如果第三方依賴庫(kù)在多個(gè)組件中都有使用,考慮將這些第三方依賴下沉到底層組件庫(kù)中統(tǒng)一管理,防止版本號(hào)沖突。

5. 數(shù)據(jù)存儲(chǔ)

  1. 盡量不要使用數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù),特殊情況除外。某些ORM框架需要數(shù)據(jù)庫(kù)表集中管理,這樣不利于實(shí)行業(yè)務(wù)模塊組件化。
  2. 使用SharedPreferences時(shí),每個(gè)業(yè)務(wù)模塊只管理自己模塊需要的數(shù)據(jù),SharedPreferences文件名需要通過(guò)業(yè)務(wù)前綴來(lái)區(qū)分,防止不同組件間數(shù)據(jù)發(fā)生沖突。
  3. 當(dāng)某些數(shù)據(jù)需要全局共享時(shí),可以考慮下沉到底層模塊。

6. 組件生命周期管理

當(dāng)業(yè)務(wù)組件需要在應(yīng)用的Application.onCreate()里進(jìn)行初始化時(shí),我們要在該組件里引入生命周期管理。

7. 發(fā)布本地maven庫(kù)

我的組件都是采用maven進(jìn)行管理的,在殼工程集成時(shí)直接通過(guò)maven引用組件。

前期開發(fā)測(cè)試時(shí),請(qǐng)先在本機(jī)發(fā)布maven庫(kù),這樣方便隨時(shí)修改更新。 在library module的根目錄下新建一個(gè)maven_local.gradle文件:


maven_local.gradle文件的配置如下:

apply plugin: 'maven'
uploadArchives {
    repositories.mavenDeployer {
        pom.version = '1.0.0'
        pom.artifactId = 'loginlocal'
        pom.groupId = 'com.hjy.app'
        repository(url: "file:///Users/hjy/.m2/repository/"
    }
}
  • version:maven庫(kù)的版本號(hào),初始版本都從1.0.0開始;
  • groupId:maven庫(kù)的組,你自己統(tǒng)一定義;
  • artifactId:maven庫(kù)的id,通常為業(yè)務(wù)模塊名,為了與遠(yuǎn)程庫(kù)區(qū)分,本地庫(kù)請(qǐng)加local后綴;
  • repository:其中"file:///Users/hjy/.m2/repository/"替換成自己本機(jī)的gradle緩存目錄,在mac中g(shù)radle的緩存目錄路徑為~/.m2/repository/;

在library module的build.gradle里增加發(fā)布腳本的引用"apply from: './maven_push.gradle'",然后點(diǎn)擊"IDE右側(cè)Gradle -> Gradle projects -> 業(yè)務(wù)module -> Tasks -> upload -> uploadArchives",最后會(huì)生成并上傳一個(gè)本地的maven庫(kù)。

在本地測(cè)試時(shí),你可以像下面這樣直接引用本地maven組件庫(kù)了。
在工程根目錄下的build.gradle里增加你本地maven庫(kù)地址:

allprojects {
    repositories {
        maven { url 'file:///Users/syl/.m2/repository/' }
    }
}

然后你就可以直接通過(guò)maven引用你的組件庫(kù)了:

compile 'com.hjy.app:loginlocal:1.0.0'

8. 發(fā)布遠(yuǎn)程maven庫(kù)

如果你的組件庫(kù)測(cè)試通過(guò),最后需要將release版本發(fā)布在遠(yuǎn)程maven服務(wù)器上,在殼工程集成時(shí),采用遠(yuǎn)程依賴的方式。與發(fā)布本地maven庫(kù)相似,在library module的根目錄下新建maven_push.gradle文件,然后在module的build.gradle里,將發(fā)布本地maven庫(kù)的腳本切換成"apply from: './maven_push.gradle'"即可。

apply plugin: 'maven'
apply plugin: 'signing'

configurations {
    deployerJars
}

repositories {
    mavenCentral()
}

uploadArchives {
    repositories {
        mavenDeployer {
            pom.version = '1.0.0'
            pom.artifactId = 'login'
            pom.groupId = 'com.hjy.app'

            //請(qǐng)改為自己的maven服務(wù)器地址
            snapshotRepository(url: 'http://127.0.0.1/nexus/repository/maven-snapshots/') {
                authentication(userName: '***', password: '***')
            }

            repository(url: 'http://127.0.0.1/nexus/repository/maven-releases/') {
                authentication(userName: '***', password: '***')
            }
        }
    }
}

// type顯示指定任務(wù)類型或任務(wù), 這里指定要執(zhí)行Javadoc這個(gè)task,這個(gè)task在gradle中已經(jīng)定義
task androidJavadocs(type: Javadoc) {
    // 設(shè)置源碼所在的位置
    source = android.sourceSets.main.java.sourceFiles
}

// 生成javadoc.jar

task androidJavadocsJar(type: Jar) {
    // 指定文檔名稱
    classifier = 'javadoc'
    from androidJavadocs.destinationDir
}

// 生成sources.jar
task androidSourcesJar(type: Jar) {
    classifier = 'sources'
    from android.sourceSets.main.java.sourceFiles
}

// 產(chǎn)生相關(guān)配置文件的任務(wù)
artifacts {
    archives androidSourcesJar
    archives androidJavadocsJar
}

把repository里的url替換成你自己的maven服務(wù)器地址,用戶名密碼換成你自己的maven賬號(hào)即可。

9. 文檔要求

每個(gè)組件都要維護(hù)好說(shuō)明文檔,通常都是一個(gè)readme文件。一般包含以下說(shuō)明:

  1. 組件的功能介紹;
  2. 組件怎么集成,以及注意事項(xiàng);
  3. 組件功能使用說(shuō)明;
  4. 組件歷史版本記錄;

盡量做到團(tuán)隊(duì)內(nèi)任何一個(gè)成員,通過(guò)該文檔就能使用組件,而不需要找到組件的開發(fā)人員來(lái)講解。

10. 組件集成測(cè)試

前面說(shuō)過(guò),有一種組件開發(fā)模式,其工程結(jié)構(gòu)如下圖所示:

“Helloworld”是我們的應(yīng)用殼工程,“ModuleA”、“ModuleB”、“ModuleC”分別是3個(gè)組件,有一種做法是通過(guò)配置文件,動(dòng)態(tài)改邊某個(gè)Module是library還是application,這樣就可以直接打包調(diào)試運(yùn)行某個(gè)組件(具體做法可以網(wǎng)上搜索)。但是我說(shuō)過(guò),這樣沒法做到代碼權(quán)限管控,也沒法做到開發(fā)人員職責(zé)劃分,每個(gè)開發(fā)人員可以對(duì)任意的組件進(jìn)行修改,這顯然會(huì)造成混亂。所以我摒棄了這種模式,而是把每個(gè)組件都分割成單獨(dú)的工程,集成測(cè)試時(shí),通過(guò)maven引用來(lái)集成。

前面講過(guò),前期自己集成測(cè)試時(shí),先發(fā)布本地maven庫(kù),在殼工程集成時(shí)如下所示:

//注冊(cè)、登錄
compile 'com.hjy.app:loginlocal:1.0.0'
//用戶中心
compile 'com.hjy.app:userinfolocal:1.0.0'
//支付模塊
compile 'com.hjy.app:paylocal:1.0.0'

每個(gè)組件的id都加了一個(gè)local后綴,這是為了區(qū)分我們代碼引用的是本地的maven組件庫(kù),還是遠(yuǎn)程的正式maven組件庫(kù)。

如果測(cè)試時(shí),發(fā)現(xiàn)了bug,只需要把組件庫(kù)本地重新發(fā)布一下,然后殼工程的gradle文件刷新同步一下就可,不用去改版本號(hào),因?yàn)檫@只是你本地的庫(kù),不會(huì)與別人的發(fā)生沖突。

最后測(cè)試通過(guò)之后,我們會(huì)發(fā)布到自己的maven服務(wù)器上,這個(gè)時(shí)候殼工程的build文件如下所示:

//注冊(cè)、登錄
compile 'com.hjy.app:login:1.0.0'
//用戶中心
compile 'com.hjy.app:userinfo:1.0.0'
//支付模塊
compile 'com.hjy.app:pay:1.0.0'

注意,這里組件的id都去掉了local后綴,同時(shí)組件的版本號(hào)必須每發(fā)布一次升一次級(jí),并做好版本變更記錄。

系列文章
Android組件化開發(fā)實(shí)踐(一):為什么要進(jìn)行組件化開發(fā)?
Android組件化開發(fā)實(shí)踐(二):組件化架構(gòu)設(shè)計(jì)
Android組件化開發(fā)實(shí)踐(三):組件開發(fā)規(guī)范
Android組件化開發(fā)實(shí)踐(四):組件間通信問題
Android組件化開發(fā)實(shí)踐(五):組件生命周期管理
Android組件化開發(fā)實(shí)踐(六):老項(xiàng)目實(shí)施組件化
Android組件化開發(fā)實(shí)踐(七):開發(fā)常見問題及解決方案
Android組件化開發(fā)實(shí)踐(八):組件生命周期如何實(shí)現(xiàn)自動(dòng)注冊(cè)管理
Android組件化開發(fā)實(shí)踐(九):自定義Gradle插件
Android組件化開發(fā)實(shí)踐(十):通過(guò)Gradle插件統(tǒng)一規(guī)范

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,769評(píng)論 25 709
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,913評(píng)論 2 59
  • Android組件化項(xiàng)目地址:Android組件化項(xiàng)目AndroidModulePattern Android組件...
    半灬邊灬天閱讀 2,996評(píng)論 4 37
  • 不怕跌倒,所以飛翔 組件化開發(fā) 參考資源 Android組件化方案 為什么要組件化開發(fā) 解決問題 實(shí)際業(yè)務(wù)變化非常...
    筆墨Android閱讀 3,094評(píng)論 0 0
  • 僅僅是有氧消耗是很難消耗到體脂的,根據(jù)訓(xùn)練情況,會(huì)先消耗體內(nèi)的食物,待逐漸加入無(wú)氧,將運(yùn)動(dòng)量提上去了,訓(xùn)練所...
    奔跑的Danielle閱讀 415評(píng)論 3 4

友情鏈接更多精彩內(nèi)容