天天看點

通過Gradle自動實作Android元件化子產品建構

為什麼我們要用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。

廢話少說,一下是通過

快速實作Android元件化建構的流程。

Demo位址:

SimpleCalces

項目結構:

simple_calces_dir

引入依賴庫

在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"
           

在項目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
        }
    }

}
           

在modules(子子產品)引入子產品自動化建構插件 (注意:不需要手動配置com.android.library或com.android.application)

apply plugin: 'calces.modules'
           

這樣我們就完成了元件化的建構了,是的,我們不再需要再手動管理單個元件了與App的建構了,通過

,我們能實作快速的元件化建構與多App同時建構。

那麼問題來了,我們如何實作元件間的通信呢?在簡單的項目中,推薦該Demo一樣,通過使用Android

隐式Intent

來實作元件間通信。在中大型項目中,筆者推薦使用阿裡的路由解決方案:

ARouter

。具體使用方法參考官方文檔就可以了,使用方法十分簡單。

注意:在使用隐式Intent實作元件件通信的時候需要注意找不到相應元件異常:java.lang.IllegalStateException: Could not execute method of the activity。導緻這個異常的原因是找不到目标元件導緻的,是以在實際開發的時候,需要捕獲這一異常,并且根據項目實際情況來進行實際的處理。使用ARouter架構則能通過設定降級政策來實作異常處理(檢視ARouter文檔了解更多)。

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

元件化建構簡述

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

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

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。

我們隻需要使用

就能快速實作我們需要的功能。

按照

的教程,我們得知,實作

隻需要三個步驟:

  1. 在項目的build.gradle中配置AppConfig
  2. 在業務子產品中引入子產品自動化構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子產品,通過對項目實行合理的劃分和引入

就能夠快速實作元件化建構了。

結論:通過

能輕松實作業務元件的管理,多APP的快速建構。當我們的業務元件隻有4個的時候,可能無法展現Calces的優勢,但是如果我們的業務元件有40個的時候,

給我們帶來的優勢就非常明顯了。我們可以通過靈活依賴不同的元件,實作快速建構多個APP的目的。就像

的介紹圖案一樣,把元件當成積木來使用。

如何測試

Android自動化測試展開來說是一個非常大并且不算簡單的工程,在這裡筆者不打算展開來說。隻是簡單的介紹元件化建構如何讓我們更友善地去測試。

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

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

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

占比如下圖所示:

通過Gradle自動實作Android元件化子產品建構

從上文知道,在我們的元件化分的時候,會劃分一個基礎依賴庫(superLib)。基礎依賴庫為我們的項目提供了基本的支援,并且該庫在項目中是比較穩定、并且不包含業務邏輯的,是以在基礎依賴庫中,我們應該大量應用單元測試。而內建測試則适用于我們的資料依賴庫(dataLib)中,我們可以通過內建測試來驗證産品代碼與資料子產品的互動。而我們的業務子產品中包含了大量的業務邏輯,這部分是經常變動的部分,我們可以為我們的業務子產品編寫一些UI自動化測試代碼,但是因為業務(界面)經常變動的原因,是以這部分測試代碼是難以維護,并且複用性十分低的。。

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

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

小結

通過

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

  1. 大型項目如何合理劃分元件子產品
  2. 當項目的元件數量非常多的時候如何管理

第二個問題,可以通過

快速解決,至于第一個問題,筆者給出的指導就是,業務子產品在合理的情況下要盡可能的小,因為越小的子產品,越容易達到高内聚低耦合的目的。讀者不需要擔心項目子產品劃分得過于細不便于管理的問題,因為

能夠輕松幫你管理好各個子產品。

現在加Android進階開發群;701740775,可免費領取一份最新Android進階架構技術體系大

綱和進階視訊資料,以及這些年年積累整理的所有面試資源筆記。歡迎在群裡探讨交流移動開發相關的技術跟問題,加群請備注csdn領取xx資料