天天看點

如何簡單快速搭建 Android 大倉

書接上文,上回提到 B 站Android團隊為了解決元件化後協作上的問題,已經采用了

大倉(monorepo)

的方案來組織代碼。

國内實踐大倉的團隊少之又少,更别提 Android 的大倉了,幾乎沒有來自其它團隊的可借鑒經驗。在這條路上,我們可以算作先行者。本文粗陋,文中所列思路不可能适用所有團隊,僅給同樣想實踐Android 大倉的人些許啟發。

一個标準的 Gradle 項目

首先回顧一下 Android 項目的組織方式。自從13年開始官方逐漸遷移到 

Android Studio

 做為 IDE 後,

Android 項目的開發和編譯就綁在 Gradle

 上了。

一個

标準的 Gradle 項目

結構如下所示:

MyApp/
├── build.gradle 
├── settings.gradle 
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar  
│       └── gradle-wrapper.properties  
├── gradlew  
├── gradle.properties 
└── app
     ├── build.gradle
     └── src
          └── main
              ├── java
              ├── res
              └── AndroidManifest.xml
           

通常,會有多個Gradle Module存在:

MyApp/
├── build.gradle 
├── settings.gradle 
├── app
│     ├── build.gradle
│     └── src
├── lib1
│     ├── build.gradle
│     └── src
└── lib2
      ├── build.gradle
      └── src
           

其中 

settings.gradle

 會注冊所有的 Module

include ':app', ':lib1', ':lib2'
           

多倉庫

随業務的擴張,Module 數量會越來越多。遵循多數人實踐過的元件化的思路,按業務分倉庫存放便理所當然:

android group/
  ├── MyApp/ 
  │     ├── build.gradle
  │     └── settings.gradle
  ├── app1/
  │     ├── build.gradle
  │     └── settings.gradle
  ├── app2/
  │     ├── build.gradle
  │     └── settings.gradle
  └── libs/
        ├── build.gradle
        └── settings.gradle
           

每個倉庫都是一個

标準 Gradle 項目

,通過 

publishing

 插件将module 都上傳 aar(或者jar)到 maven私服(如

nexus

)上,再在 

MyApp/build.gradle

 中以 maven 元件的形式依賴它們,最終打包成apk:

repositories {
    maven {
        name = "myRepo"
        url = "http://myrepo.example.com/android"
    }
}
dependencies {
    implementation 'com.example.android:app-a:1.0.0'
    implementation 'com.example.android:app-b:1.0.0'
    implementation 'com.example.android:lib-a:1.1.0'
}
           
[圖檔上傳失敗...(image-7a44b2-1546505515555)]

此時的代碼組織方式便是上文中所述的

形态(可能許多團隊正處于目前階段)。

多倉到大倉

那麼,如何既能快速搭建出适用于 Android 的大倉,又能不影響目前的團隊協作流程,還要盡量避免遷移帶來的開發效率降低?

經過一段時間的深入研究 Gradle API,終于找到一個簡單快速的可行方案——

composite builds

上面說過,其實每個倉庫都是按業務分離的标準的 Gradle 項目,那麼就可以通過Gradle 官方提供的一個直接引入其它項目的API——

includeBuild

——快速将所有倉庫組織起來。

在 

MyApp/settings.gradle

 中直接引入其它 Gradle 項目:

includeBuild '../app1'
includeBuild '../app2'
includeBuild '../libs'
           

另外比較令人驚喜的是,如Gradle 官方所說,

includeBuild

會自動替換依賴

com.example.android:app-a

為有對應聲明的module,如 

project(:app1:app-a)

。這樣仍然可以用原有的依賴寫法,什麼都不用改,基本沒有遷移工作量。

具體示例可以見官方示例項目:

https://github.com/gradle/gradle/tree/master/subprojects/docs/src/samples/compositeBuilds/hierarchical-multirepo

而且,使用 

includeBuild

 能保留目前的開發流程不變,每個子產品仍釋出到 maven 上,不破壞既有協作流程。各個業務的開發,通過Android Studio 打開自己項目的目錄即可,可以說幾乎沒有開發效率的影響。

解決了各個項目合并問題,另外一個就是要保證大倉的可維護性。

上文講過,依然沿用之前分層的方式,按約定的檔案夾組織:

<root dir>
    ├── build.gradle
    ├── settings.gradle 
    ├── app/
    │    ├── app-a
    │    │    ├── src 
    │    │    └── build.gradle
    │    ├── app-b
    │    │    ├── src
    │    │    └── build.gradle   
    │    ├── build.gradle
    │    └── settings.gradle
    │
    ├── common/
    │    ├── common-a
    │    │    ├── src
    │    │    └── build.gradle
    │    ├── build.gradle
    │    └── settings.gradle
    │
    ├── framework/
    │    ├── lib-a
    │    │    ├── src
    │    │    └── build.gradle
    │    ├── build.gradle
    │    └── settings.gradle
    │
    └── MyApp
         ├── src
         └── build.gradle
           

各個業務方的代碼隻需要按層級對号入座即可。

對号入座的方式有很多種,最簡單的便是直接拷貝項目到對應目錄,而如果要保留原倉庫的送出記錄,則可以使用 git filter-branch 和 git update-index 等指令(略過不表╮( ̄▽ ̄)╭)。

收斂合并權限

人總是會犯錯的,為了不讓近百名開發成員在一個倉庫裡打架,我們需要在 gitlab 權限配置設定的基礎上,通過API實作自動化的方式來合并代碼。

每個檔案夾(或者子產品)可以添加一個配置檔案,如

OWNERS

,業務團隊自己配置設定 owner和reviewer。

<root dir>
    ├── app
    │    ├── OWNERS
    │    └── app-a
    │          └── OWNERS
    ├── common
    │    ├── OWNERS
    │    └── common-a
    │          └── OWNERS
    ├── framework
    │    ├── OWNERS
    │    └── lib-a
    │          └── OWNERS
    └── MyApp
         └── OWNERS
           

通過gitlab webhook及note api來實作一個自動化工具:

當開發人員送出一個新的 Merge Reqeust 時,工具找到有變更檔案夾的對應 owner 及 reviewer,提醒他來review 和操作合并;當他在MR中送出merge指令時,由自動化工具執行合并操作。

綜述

  1. 通過 Gradle 的

    includeBuild

    将所有分開的倉庫合并到一起,并按一定的目錄層級組織各個子項目。
  2. 通過 gitlab 的 api 實作一個自動化工具來合并代碼。

通過上述兩個步驟,便打造了一個大倉雛形。然而這隻是大倉的第一步,未來還有很多工作呢…

關于大倉,本文隻簡單描述了一下方案大緻思路,行文粗糙,希望對想實踐大倉的你有所幫助,如有疑問歡迎評論留言。

歡迎加入Android進階交流群;701740775。進群可免費領取一份最新技術大綱和Android進階資料。請備注csdn

繼續閱讀