引用其他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【附效果图附源码】

©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页