引用其他project的module,根據參數自動配置依賴,repo管理多個 Project

前言

在開發中遇到這樣一個問題,在工作的project(以下簡稱Project A)中,用到了Fragmentation(以下簡稱Project B) 庫的三個module,這個庫是我在維護,平時更改庫中的一些bug,需要先使用一段時間,再推到github,併發布到jcenter, 所以在我的工作項目中,是直接使用本地的代碼,沒有使用jcenter去引用它。

這就遇到一個問題,在Project A 中改完 Project B的三個module,在等到發佈的時候,就需要手動把代碼拷貝一份到Project B中。如何能讓這個過程簡單點呢?

有小夥伴想到了,可以使用軟連接,這樣改完工作項目中的這三個module,就不再重複複製代碼了。如果是多人協作開發,就不行了。

把Project B 這三個module ,分別使用git管理,整個工程項目使用repo 來管理,這樣不管是哪個project 都可以方便的使用這三個module,但是這樣對Project B 的改動較大。如果Project B 發佈後,Project A 想通過jcenter 來引用這三個module,也不是很方便。

於是在想,使用repo 來管理不同的Project,repo 本質是來管理多個git的,所以是project還是model,沒有差別。這樣可以來通過repo 來管理這個

另外兩個問題:
在Android studio中 一個project 如何使用另外一個project的module呢?
在本地沒有 Project B,如何讓Project A 自動通過jcenter來引用?

使用repo 來管理項目

repo 本質是來管理多個git的,所以無論是project 還是module,只要用git 來管理,那麼他們就可以被repo管理

1、repo安裝

折騰過Android 源碼的同學,應該對這個很熟悉,可以直接去配置default.xml,然後按照自己的思路,就可以

創建bin 目錄,並加入到環境變量

$ mkdir ~/bin
$ PATH=~/bin:$PATH

在bin 目錄下,下載repo 工具

$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo

2、創建default.xml

repo 是用python開發的工具, 來管理不同項目的git,需要通過一個配置文件default.xml,來告訴他有哪些項目,遠程地址是什麼,本地路徑是什麼,review 等等

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
    <!-- -->
    <remote name="github" fetch="https://github.com/JantHsueh"  />
    <remote name="aliyun" fetch="https://code.aliyun.com/cmoon"  />
    
    <default remote="aliyun" revision="master" sync-j="4"/>

    <project name="cm-android.git" path="xw" />
    <project name="Fragmentation.git" path="Fragmentation"  remote="github"/>

</manifest>

remote 遠程倉庫地址配置,可以多個。

  • name: 名字,也用於子倉庫的 git remote 名稱(.git/config 裏的 remote)
  • alias: 別名,可省略,建議設爲 origin, 設置了那麼子倉庫的 git remote 即爲此名,方便不同的 name 下可以最終設置生成相同的 remote 名稱
  • fetch: 倉庫地址前綴,即 project 的倉庫地址爲: remote.fetch + project.name
  • pushurl: 一般可省略,省略了則直接用 fetch
  • review: Gerrit code review 的地址,如果沒有用 Gerrit 則不需要配置(也就不能用 repo upload 命令了)
  • revision: 使用此 remote 的默認分支

default配置默認遠程倉庫地址

  • remote :它的值 是上面remote 標籤 配置的name 值,表示遠程倉庫地址
  • revision : 遠程分支
  • sync-j : 使用線程數

project

  • name : 遠程倉庫的項目名,配合remote標籤的fetch值,共同組成完整倉庫地址:remote.fetch + project.name
  • path:工程在本地的存儲路徑
  • remote :它的值 是上面remote 標籤 配置的name 值,表示遠程倉庫地址。如果沒有配置,使用default中的配置

更多參數配置,查看官方文檔repo Manifest Format

3、repo 初始化 和代碼下載

# 初始化 repo  default.xml 文件 會下載到   .repo/manifests/ 目錄下 
repo init -u https://github.com/anlory/manifest
# 根據配置,下載代碼
repo sync

至此,repo就把這兩個project 管理起來了,在項目中應該如何配置project直接的關係呢?

如何引用其他project?

default.xml 在 .repo/manifests/ 目錄下 ,爲了在project 中 能方便的通過 default.xml 控制項目,所以創建default.xml 軟連接,放在project中,並加入到.gitignore 中

在setting.gradle 中,指定 module 的路徑,這樣就可以指定到其他project 中的 module

include ':app', ':mvvm'

//設置全局變量,在setting.gralde 和 build.gradle 中設置環境變量是不一樣的
gradle.ext.localFragmentation = false

//在default.xml 中判斷,是否有對應的project,如果有,repo sync 後 本地就有對應的代碼,就配置使用本地工程代碼
def manifest = new XmlParser().parse("${rootProject.projectDir}/default.xml")
manifest.project.each {
    it.attributes().each { k, v ->
		// path 對應的值包含 Fragmentation 字段
        if (k == 'path' && v.contains('Fragmentation')) {

            gradle.ext.localFragmentation = true

			//指定Fragmentation工程的路徑,在本示例中,兩個工程的目錄是同級的
            def path = '../Fragmentation'

            include ':Fragmentation'
            project(':Fragmentation').projectDir = new File(path)

            include ':fragmentation'
            project(':fragmentation').projectDir = new File(path, 'fragmentation')

            include ':fragmentation_core'
            project(':fragmentation_core').projectDir = new File(path, 'fragmentation_core')

            include ':fragmentation_swipeback'
            project(':fragmentation_swipeback').projectDir = new File(path, 'fragmentation_swipeback')

        }
    }
}

gradle.ext.xx 和rootProject.ext.xx的用法差不多,只是變量存放的位置不同

  • 在build.gradle 中配置全局變量 使用 rootProject.ext.
  • 在setting.gradle中配置全局變量使用 gradle.ext

更多全局變量的使用,可參考這篇文章 gradle使用技巧之全局變量

如何根據參數,自動配置不同的依賴?

這個就很簡單了,根據上面設置的全局變量來判斷

dependencies {
    if (gradle.ext.localFragmentation) {
        api project(':fragmentation')
        api project(':fragmentation_swipeback')
    } else {
        api 'me.xuexuan:fragmentationx:1.0.6'
        api 'me.xuexuan:fragmentationx-swipeback:1.0.6'
    }
 }

當然可以有更多的玩法:

下面代碼是參考這裏的,需要引用哪個項目,從gradle.properties的配置中獲取。


def moduleVersions = new Properties()
def moduleVersionsFile = new File("${project.projectDir}/gradle.properties")
moduleVersions.load(moduleVersionsFile.newDataInputStream())

dependencies {
    def projects = moduleVersions.stringPropertyNames()
    rootProject.subprojects.each {
        if (it.name != 'host') {
            implementation it
            projects.remove(it.name)
        }
    }
    projects.each {
        //爲了方便引用,這裏要求我們上傳到 maven 的各模塊的包遵循一定的規則,groupid 需要保持一致,
        // artifactid 最好是以子 module 的 project.name 來命名,如果不是這樣的規則,就需要自己修改 gradle 腳本啦
        implementation "me.ailurus.repo:${it}:${moduleVersions.getProperty(it)}"
    }
}

結語

在我看來,上面這種方式,算是project 之間的模塊化,由於 project 可以多module的原因,很容易在多個project裏 使用空 application 項目來打包apk

參考:
使用 repo 組織 Android 工程

Gradle Repo:一個能管理多個Git倉庫,又能快速切換分支的Gradle插件

用repo管理自己的倉庫

將數據從settings.gradle傳遞到build.gradle

Android Studio在同一個窗口中打開多個Project【附效果圖附源碼】

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