Android組件化問題思考

當項目開始膨脹的時候

當一個工程愈來愈大,功能愈來愈複雜以後,成員愈來愈多的狀況下,如何維護一個巨大的安卓項目呢?php

第一階段,你們確定都是會把公共模塊什麼的都抽取出來,封裝成aar,以後經過maven的方式引入。java

第二階段,引入路由以及spi,把項目打散成一個個子module,而後每一個人負責一兩個模塊之類的,這樣就能保證並行開發了。android

第三階段,當項目臃腫到編譯速度愈來愈慢的狀況下。這個時候會先抽象一個殼工程,而後把因此的子項模塊用aar的方式引入這個殼,以後會把每一個業務放在一個倉庫內,這樣多個業務之間就不會出現代碼衝突之類的問題了。git

這個時候會出現另一些更困擾的問題。github

  1. 殼工程是否是全部業務倉庫都須要擁有一份,那麼殼工程代碼同步怎麼辦?
  2. 各個倉庫的aar版本問題?不一樣branch 須要使用不一樣的aar版本如何作到統一管理?
  3. 萬一我要調試別人的倉庫瞭如何調試呢?

遇事不決找輪子

那麼有沒有現成的輪子能夠解決這些工程化以後會碰到的問題呢?json

Gradle Repo 容我給你們安利個項目,咱們當前項目使用的輪子就是這個。Github傳送門app

做者對於這個倉庫的描述是這樣的。maven

Gradle Repo是基於Gradle寫的一個插件,用於管理多個Git倉庫,支持方便快捷的切換分支。在根項目中會有一份配置清單repo.xml,用於描述模塊來源、工程結構以及依賴關係。gitlab

主要作了三件事情:post

從各個遠程倉庫clone代碼到指定目錄路徑下。經過Git的exclude而不是submodule。 動態include模塊,並模塊間的依賴關係,切換至指定分支。

文字描述上可能仍是有些不夠清晰哦,咱們經過一張做者的圖片去分析這個功能。

而後我本身寫了個mock的repo.xml的文件,咱們經過這個xml來簡單說下作了什麼。

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
 
    <substitute project=":module" targetModule="com.a.b:c"/>

    <module name="RouterLib" origin="https://github.com/Leifzhang/Router-Android.git" srcBuild="false" substitute="com.github.leifzhang:routerLib" />
        
</manifest>
複製代碼

這個是我根據項目內生成的一個高度類似的模版。

  1. substitute標籤表明的是當前項目下的setting內部的project名,其中targetModule表明的是咱們須要替換的aar版本。
  2. module 則表明咱們想clone的遠端的模塊,origin表明倉庫地址,srcBuild表明當前是否打開依賴,substitute則表明把遠端的implementation更換成本地的project。

當項目使用了Gradle Repo調整以後,咱們能夠隨意的拔插咱們須要的模塊,同時把多個模塊倉庫組合在一塊兒同時編譯。同時在ci上的則仍是經過implementation依賴的倉庫,咱們在開發的時候不會影響到別的業務線的開發,同時在不一樣的因爲每一個倉庫都是獨立的gitlab,因此在branch管理上也會有個自然的優點。

可是這個方案真的天衣無縫嗎??

其實也不是,那麼因爲項目散落在不一樣的倉庫內,因此必然會出現一個問題,如何統一管理項目內的aar版本呢??????

不知道各位有沒有注意過前一陣子有個老哥寫的文章叫JakeWharton評價個人代碼像是在打地鼠?。其實jake大神說的configurations.all就是這裏的解決方案了。

gradle configurations.all

那麼讓我給你們簡單的介紹下,configurations.all的做用就是強制拉平項目內的maven aar版本號。若是當項目經過implementation依賴引入了不一樣版本的aar的狀況下,會以configurations.all內定義的版本爲準,忽略掉項目內使用的差別版本。

configurations.all {
    resolutionStrategy {
        force "com.android.support:appcompat-v7:28.0.0"
    }
}
複製代碼

上面的代碼的意思就是,強制項目內的supportv7版本到28.0.0版本上去。

經過gradle plugin升級這個能力

若是簡單的使用configurations,仍是會出現每一個業務模塊都須要處理的狀況,沒法把這個能力收束到一個盒子內,這個時候咱們能夠考慮經過一個gradle plugin,自定義一個task的方式,對這個能力進行一次拓展。

定義dep版本配置

首先咱們須要定義一份遠端的和branch版本相關的gradle文件,這個文件內能夠定義好咱們之前在工程目錄下所熟悉的maven倉庫的版本。

dep = [
            fastjson                 : "com.alibaba:fastjson:${fastjsonVersion}",
            //三方控件
            androidSupportV4         : "com.android.support:support-v4:${androidSupportV4Version}",
            androidSupportV7         : "com.android.support:appcompat-v7:${androidSupportV7Version}",
            androidLifecycle         : "android.arch.lifecycle:runtime:${androidLifecycleVersion}",
            androidLifecycleCommon         : "android.arch.lifecycle:common:${androidLifecycleVersion}",
            androidLifecycleCommonJava8    : "android.arch.lifecycle:common-java8:${androidLifecycleVersion}",
            androidLifecycleCompiler : "android.arch.lifecycle:compiler:${androidLifecycleVersion}",
            androidLifecycleExtensions:"android.arch.lifecycle:extensions:${androidLifecycleVersion}",
            recyclerview             : "com.android.support:recyclerview-v7:${recyclerviewVersion}",
            androidSupportAnnotations: "com.android.support:support-annotations:${androidSupportVersion}"
            ]

複製代碼

自定義gradle task

而後咱們自定義一個gradle插件,而後生成一個本身的task任務,同步命令被執行的時候,咱們就經過接口調用或者git操做的方式去獲取遠端的gradle,而後更改項目的gralde configurations.all的方式,去吧項目內的aar版本拉平。

class AATask : DefaultTask() {

    @TaskAction
    fun apply() {
        ##僞代碼 從遠端拉取Dep配置
        //強制更換項目內配置
        forceConfigVersion(project)
    }
    
    fun forceConfigVersion(project: Project) {
        project.subprojects {
            val depModuleSelectorNotations = mutableListOf<String>()

            project.extensions.extraProperties.properties.forEach { key, any ->

                if (any!=null && key!=null&&key.endsWith("dep")){
                    if (any is Map<*, *>){
                        collectDepModuleVersionSelectorNotations(depModuleSelectorNotations, any)
                    }
                }
            }

            it.configurations.all { configuration ->
                configuration.resolutionStrategy.force(depModuleSelectorNotations)
            }
        }


    }

複製代碼

具體詳細的內容涉及到公司代碼就不和你們詳細的展開了,思路核心就是一切三方庫的版本以遠端的branch做爲標準。

總結

本文只是一篇科普文章,並不涉及到任何代碼分析,若是有什麼得罪的地方,你也打不到我。

相關文章
相關標籤/搜索