不用寫一句代碼,自動實現 Android 組件化模塊構建

<p align="center">

<img src="https://raw.githubusercontent...; alt="Material Render Phone">

</p>

背景

隨着App的不斷迭代,業務會變得越來越複雜,業務模塊會越來越多,且每個模塊的代碼也會變得越來越多。爲了應對這一場景,我們需要把不同的業務模塊劃分成一個個組件,在修改業務代碼的時候只需要在對應模塊修改就可以了。通過高內聚,低耦合的業務模塊來保證工程的健壯性和穩定性。現在問題來了,當組件的數量變得越來多的時候,我們如何管理業務組件呢?

原創聲明: 該文章爲原創文章,未經博主同意嚴禁轉載。
<!--more-->

爲什麼我們要用Gradle管理組件呢?

先來看看Android組件化需要實現的目標。(什麼是組件化構建?)

  1. 按照業務邏輯劃分模塊
  2. 項目模塊能夠單獨啓動測試
  3. 能夠根據需求引入或刪除某些業務模塊
  4. 通過不同模塊的組合,組成不同的App

對於第一點:需要根據技術架構和業務架構來劃分模塊,這裏需要根據實際情況來考慮。我們需要優化的是第二、三、四點。

對於第二點:Android是通過應用com.android.application或com.android.library來決定該模塊是以App模式還是以Library模式構建。App模式和Library模式的最大區別就是,App能夠啓動,而Library不可以。所以如果我們的模塊能獨立啓動的話,我們需要每次手動去改動模塊的build.gradle文件。好一點的做法定義一個布爾值來判斷是否處於debug模式,但是這裏有個問題是,不是每個模塊都能獨立啓動的。所以無論採用何種方案,都需要我們手動管理。

對於第三點:當我們開發好業務模塊後,可能我們需要頻繁的新增或刪除某些業務模塊。如果是這樣的話,我們也是需要頻繁手動修改App的build.gradle。

對於第四點:有時候,我們可能會在不同的App中引用相同的組件(例如:滴滴的普通版和企業版,普通版包含企業版的功能),這個時候,我們也不希望要頻繁手動管理組件依賴,特別是在組件還可以獨立運行的時候。

所以,在我們實踐組件化的時候,最大的問題就是,我們需要頻繁的手動build.gradle文件來管理組件應用的插件和App的依賴。

使用Gradle來管理組件

先安利下筆者寫的Gradle插件:Calces。如果覺得這個插件有用的話,可以star下,如果你有更好的想法的話,可以向我提交pull request。

廢話少說,以下是通過Calces快速實現Android組件化構建的流程。

你的支持,是我前進的動力,如果覺得有幫助的話,可以點下star👍

Demo地址:SimpleCalces

項目結構:

simple_calces_dir

  1. 引入依賴庫

在Gradle 2.1及更高版本的插件構建腳本代碼:

在項目的build.gradle中

buildscript {
    ...
}
plugins {
  id "calces.modules" version "1.0.11"
}

在較舊版本的Gradle中或需要動態配置的情況下的插件構建腳本代碼:

   buildscript {
     repositories {
       maven {
         url "https://plugins.gradle.org/m2/"
       }
     }
     dependencies {
       classpath "gradle.plugin.com.tangpj.tools:calces:1.0.11"
     }
   }
   apply plugin: "calces.appConfig"
  1. 在項目build.gradle配置AppConfig
   appConfig {
       debugEnable false
   
       apps {
           app{
               modules ':library1', ':library2'
           }
       }
   
       modules{
           library1{
               mainActivity ".Library1Activity"
               applicationId "com.tangpj.library1"
               isRunAlone true
           }
           library2{
               mainActivity ".Library2Activity"
               applicationId "com.tangpj.library2"
               isRunAlone true
           }
       }
   
   }
  1. 在modules(子模塊)引入模塊自動化構建插件 (注意:不需要手動配置com.android.library或com.android.application)
   apply plugin: 'calces.modules'

這樣我們就完成了組件化的構建了,是的,我們不再需要再手動管理單個組件了與App的構建了,通過Calces,我們能實現快速的組件化構建與多App同時構建。

那麼問題來了,我們如何實現組件間的通信呢?在簡單的項目中,推薦該Demo一樣,通過使用Android隱式Intent來實現組件間通信。在中大型項目中,筆者推薦使用阿里的路由解決方案:ARouter。具體使用方法參考官方文檔就可以了,使用方法十分簡單。

注意:在使用隱式Intent實現組件件通信的時候需要注意找不到相應組件異常:java.lang.IllegalStateException: Could not execute method of the activity。導致這個異常的原因是找不到目標組件導致的,所以在實際開發的時候,需要捕獲這一異常,並且根據項目實際情況來進行實際的處理。使用ARouter框架則能通過設置降級策略來實現異常處理(查看ARouter文檔瞭解更多)。

如果只是實現項目的簡單組件化,那麼看到這裏就可以了,如果希望實現更加靈活的組件化架構的讀者可以繼續看下去,下面筆者將全面分析組件化的優勢與筆者總結的組件化構建思想。

組件化構建簡述

組件化構建與其說是一種技術,不如說是一種思想。組件化構建是通過對項目重新劃分成一個個高內聚、低耦合的模塊來解決項目過於臃腫,代碼過於複雜的一種架構思想。

我們通過對Google官方的架構演示Demo todo-mvp進行拆分來對Android組件化進行深入的分析。

Demo地址:TodoCalces

todo系列app是Google android-architecture項目中爲了演示Android架構的最佳實現而編寫的一系列演示Demo。todo app的特點是,它足夠簡單,代碼量少,易於理解。但是又不會過於簡單,因爲它是一個包含完成功能的App。它實現了任務列表、任務詳情、新建任務、編輯任務、統計任務的功能。

todo-mvp實現的功能:

  • 任務列表
  • 任務詳情
  • 新增/編輯任務
  • 統計任務

我們將以todo-mvp的功能來劃分爲4個業務模塊,將底層劃分爲2個模塊,分別是superLib(提供mvp架構支持與其它的一些支持庫功能)與dataLib(數據支持模塊,Room提供底層數據庫支持功能)。對於大型項目還可以加入resLib支持模塊,用來存放公共圖片資源、字符穿資源、樣式等。

架構劃分圖如下:

Todo Calces Architecture

從架構圖可以看出,所有的業務組件都依賴底層庫,而APP又依賴於業務組件,APP組件在這裏是作爲一個獨立組件存在的。在一般的組件化實踐中,都不包含APP這個組件的,APP組件的存在是有其意義的。

首先,我們的組件化除了實現組件的獨立管理和動態配置APP所依賴的組件外,還有一個十分重要的目的就是,通過組合不同的組件,打包多個不同的APP。例如,QQ有分普通版和輕聊版,輕聊版是功能簡化版的QQ。如果我們使用組件化來管理工程的話,我們只需要把不需要的模塊移除掉就可以了。而APP組件在這裏的作用是充當一個包裝盒,把需要的組件包裝進來。並且我們可以通過控制包裝盒的樣式來配置不同的APP風格。在這裏我們可以通過Application中的Style來實現。

這裏我們還是以todo-mvp爲例,例如我們需要實現一個不包含統計功能的todo APP,按照我們的原理,我們只需要去掉statistics的依賴就可以了。

架構劃分圖如下:

Todo No Statistic Architectur

如果nostatsitcs需要不同的配色的方案的話,只需要在AndroidManifest的application標籤中配置對應的theme就可以了。

使用Calces實現todo-mvp的組件化

通過上面的分析,我們來試下對todo-mvp項目按照業務功能來劃分組件。我們先來看看劃分後的目錄:

todo_calces_dir

好了,我們已經對todo-mvp項目進行初步的劃分了。根據上面分析的理論得知,我們的業務模塊是可以單獨運行的,並且我們能夠快速構建一個不包含statistics模塊的APP。

我們只需要使用Calces就能快速實現我們需要的功能。

按照Calces的教程,我們得知,實現Calces只需要三個步驟:

  1. 引入依賴庫
  2. 在項目的build.gradle中配置AppConfig
  3. 在業務模塊中引入模塊自動化構c持續

第一點和第三點在其它所有項目中的配置都是一樣的,在這裏不作論述,下面我們看看對於TodoCalces項目,我們要如何配置AppConfig 。

appConfig {

    debugEnable false

    apps {
        app {
            mainActivity "com.tangpj.tasks.TasksActivity"
            modules ':modules:addtask',
                    ':modules:taskdetail',
                    ':modules:tasks',
                    ':modules:statistics'
        }

        app2 {
            name 'nostatistic'
            applicationId 'com.tangpj.nostatistic'
            modules ':modules:addtask',
                    ':modules:taskdetail',
                    ':modules:tasks'
        }

    }

    modules {
        addtask {
            name ":modules:addtask"
            applicationId "com.tangpj.addtask"
            mainActivity ".AddEditTaskActivity"
            isRunAlone false
        }

        taskdetail {
            name ":modules:taskdetail"
            applicationId "com.tangpj.taskdetail"
            mainActivity ".TaskDetailActivity"
            isRunAlone true
        }


        task {
            name ":modules:tasks"
            applicationId "com.tangpj.tasks"
            mainActivity ".TasksActivity"
            isRunAlone true
        }

        statistics {
            name ":modules:statistics"
            applicationId "com.tangpj.statistics"
            mainActivity ".StatisticsActivity"
            isRunAlone true
        }


    }
}

根據AppConfig可以得出,我們分別配置了2個APP,分別是app1和app2。並且app2中是沒有依賴statistics的。現在我們兩個APP運行的對比圖。

app1(帶statistics模塊):

todo_calces

app2(不帶statistics模塊):

nostatistic

從運行圖可以看出,app1和app2的配色方案是不一樣的,並且app2中不帶statistics模塊,通過對項目實行合理的劃分和引入Calces就能夠快速實現組件化構建了。

結論:通過Calces能輕鬆實現業務組件的管理,多APP的快速構建。當我們的業務組件只有4個的時候,可能無法體現Calces的優勢,但是如果我們的業務組件有40個的時候,Calces給我們帶來的優勢就非常明顯了。我們可以通過靈活依賴不同的組件,實現快速構建多個APP的目的。就像Calces的介紹圖案一樣,把組件當成積木來使用。

如何測試

Android自動化測試展開來說是一個非常大並且不算簡單的工程,在這裏筆者不打算展開來說。只是簡單的介紹組件化構建如何讓我們更方便地去測試。

並不是所有的自動化測試都一樣,它們通常在使用範圍、實現難度和執行時間上存在不同。我們一般把自動化測試劃分爲三種分別是:

  1. 單元測試:目的是測試代碼的最小單元。在基於Java的項目中,這個單元是一個方法。單元測試容易編寫,快速執行,並在開發過程中針對代碼的正確性提供寶貴的反饋。
  2. 集成測試:用來測試一個完成的組件或子系統,確保多個類之間的交互是否按預期運行。集成測試需要比單元測試需要更長的執行時間,而且更加難以維護,失敗的原因難以診斷。
  3. 功能測試:通常用於測試應用程序端到端的功能,包括從用戶的角度與所有外部系統的交互。當我們討論用戶角度時,通常是指用戶界面。因爲用戶界面會隨着時間的推移發生變動,維護功能測試代碼會變得乏味而耗時。

爲了優化投資回報率,代碼庫應該包含大量的單元測試、少量集成測試以及更少的功能測試。

佔比如下圖所示:

自動化測試金字塔

從上文知道,在我們的組件化分的時候,會劃分一個基礎依賴庫(superLib)。基礎依賴庫爲我們的項目提供了基本的支持,並且該庫在項目中是比較穩定、並且不包含業務邏輯的,所以在基礎依賴庫中,我們應該大量應用單元測試。而集成測試則適用於我們的數據依賴庫(dataLib)中,我們可以通過集成測試來驗證產品代碼與數據模塊的交互。而我們的業務模塊中包含了大量的業務邏輯,這部分是經常變動的部分,我們可以爲我們的業務模塊編寫一些UI自動化測試代碼,但是因爲業務(界面)經常變動的原因,所以這部分測試代碼是難以維護,並且複用性十分低的。。

最後,我們得出的結論是:應該把主要精力放在單元測試上,所以如果當你的精力不足以編寫所有測試代碼的時候,你應該把主要的精力放在單元測試上,而不是放在收益最小的功能測試上。

關於自動化測試,筆者給的建議就到這裏了,如果需要深入理解測試的話,可以自行查找資料,或者關注筆者的博客。後續的博客中,有可能會寫關於自動化測試相關的知識。

小結

通過Calces插件,我們在實現Android組件化時只需要關注如何合理劃分組件的架構與如何實現組件間的通信就可以了。對於Android組件化來說,最主要問題有兩個:

  1. 大型項目如何合理劃分組件模塊
  2. 當項目的組件數量非常多的時候如何管理

第二個問題,可以通過Calces快速解決,至於第一個問題,筆者給出的指導就是,業務模塊在合理的情況下要儘可能的小,因爲越小的模塊,越容易達到高內聚低耦合的目的。讀者不需要擔心項目模塊劃分得過於細不便於管理的問題,因爲Calces能夠輕鬆幫你管理好各個模塊。

歷史精選

Android開發利器之Data Binding Compiler V2 —— 搭建Android MVVM完全體的基礎

關於我

如果這片文章對你有所啓發的話,可以關注下筆者的公衆號或GitHub

掃一掃關注我:

qr

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章