组件化系列 - 模块版本管理

604 阅读5分钟

组件化一定逃不过各个组件/模块通过依赖的方式组装成一个app的结构,所以首先就要学会如何上传模块到maven仓库。

建立Maven仓库

Nexus配置

下载地址:www.sonatype.com/nexus/repos…

下载后解压文件到任意目录,进入到 bin 目录下,比如我自己的路径就是 /Users/用户名/Downloads/应用/nexus-3.29.2-02-mac/nexus-3.29.2-02/bin,然后在该目录下打开命令窗口输入 ./nexus start,这样nexus就启动起来了,在浏览器那输入 http://127.0.0.1:8081 就是可视化工作台了。登录账号是admin,默认密码在 /Users/用户名/Downloads/应用/sonatype-work/nexus/admin.password 文件内,当然首次登录后你最好设置一个自己容易记的密码。

创建Repository

可以使用自带的maven-releases和maven-snapshots,自定义仓库的话根据箭头标识按顺序点击 Create Repository,创建时注意选择 maven2 hosted 即可,最好创建snapshot和release版本。

snapshot和release区别: snapshot表示快照版本,一般用于开发阶段,maven会自动识别版本号后带-SNAPSHOT,这样我们不需要更改版本号就可以让依赖方更新库,开发时会经常上传每次更改版本号的话没必要。release是发布版本, 在发布的时候版本号都需要增加,否则依赖方无法更新库(除非把缓存都删除了重新下载依赖库)。

gradle已有的上传任务

单独创建一个 upload-aar.gradle 文件:

apply plugin: 'maven'
def POM_VERSION = '1.0.0'
def POM_ARTIFACT_ID = 'biz_home'
def POM_GROUP_ID = 'com.sun.biz'
def POM_PACKAGING = 'aar'
def USERNAME = 'admin'
def PASSWORD = 'admin123'
def REPOSITORY_URL = 'http://localhost:8081/repository/sun/'
def REPOSITORY_URL_SNAPSHOT = 'http://localhost:8081/repository/sun-snapshot/'

def getPomVersion(pomVersion) {
    String version = pomVersion
    // gradle.properties内声明
    if(isSnapshot.toBoolean()) {
        version += "-SNAPSHOT"
    }
    return version
}

uploadArchives {
    repositories {
        mavenDeployer {
            snapshotRepository(url: REPOSITORY_URL_SNAPSHOT) {
                authentication(userName: USERNAME, password: PASSWORD)
            }
            repository(url: REPOSITORY_URL) {
                authentication(userName: USERNAME, password: PASSWORD)
            }
            pom.project {
                version getPomVersion(POM_VERSION)
                artifactId POM_ARTIFACT_ID
                groupId POM_GROUP_ID
                packaging POM_PACKAGING
            }
        }
    }
}

上传模板基本可以套用,这里可以看到gradle.properties内声明了一个变量用来控制是否是快照版本:

isSnapshot = true

如果是那么就要加上后缀1.0.0-SNAPSHOT,maven就会自动识别这个是快照版本。当快照版本上传时会使用 snapshotRepository 上传,正式版本则用 repository 来上传,因此可以指定不同的url。我们可以把相关联的库放到同一个groupId下,artifactId 必须是唯一的。

使用这个上传功能需要把 upload-aar.gradle 引入到模块的build.gradle内:

apply from: 'upload-aar.gradle'

同步gradle后,可以用命令行的方式上传:

./gradlew uploadArchives

也可以用AndroidStudio自带视图去执行任务:

最后按上面的例子,使用者通过依赖快照版本的路径应该是这样的:

implementation 'com.sun.biz.biz_home:1.0.0-SNAPSHOT'

同时需要在根目录的build.gradle配置加上maven仓库的url:

buildscript {
	repository {
		maven {url 'http://127.0.0.1:8081/repository/sun-snapshot/'}
	}
}

完整的上传逻辑已经完成了,但是你会发现download下来的库没有源码,所以我们需要把源码的上传加入到 upload-aar.gradle内即可:

// 生成javadoc.jar
task androidJavadocsJar(type: Jar) {
    // 指定文档名称
    classifier = 'javadoc'
    from android.sourceSets.main.java.srcDirs
}

// 打包main目录下代码和资源的task,生成sources.jar
task androidSourcesJar(type: Jar) {
    classifier = 'sources'
    from android.sourceSets.main.java.srcDirs
}

//配置需要上传到maven仓库的文件
artifacts {
    archives androidSourcesJar
    archives androidJavadocsJar
}

自定义上传插件

gradle自带的上传任务已经足够满足一些小项目。当遇到大项目的组件化时,你可能会有几十个工程,并且一个工程中可能存在多个模块(如一个实现层、一个接口层),如果使用自带上传任务,那么需要每一个模块都放一份 upload-aar.gradle 文件,会有相当多的重复性工作,并且上传时也要多次上传(实现层上传一次,接口层上传一次)。这个时候需要自定义上传插件为了解决效率应运而生了。

先思考下这个插件是为了解决什么问题:

  • 多工程复用,只需要依赖一个plugin就能使用。
  • 工程内多模块执行一次任务就能全部上传(这里可能有疑问,为啥我只改了实现层代码还需要把接口层又上传一遍,不是做无用功了吗?其实一个工程的所有相关模块最好版本都是保持一致的,在大项目里你就知道这样的版本管理有多省心了)。
  • 后续根据需求可以在上传之前做其他的校验,比如校验是否合并过主分支的代码等逻辑,如果不通过就终止上传。

对于gradle plugin的开发没有太多的文章去讲解某个插件怎么做之类的,主要还是参考 gradle plugin官网。相信逻辑上并不会很难,只是需要查找和熟悉各种api。

大致说下开发这个上传插件的思路:

  1. 开发gradle plugin的模板代码,提供插件名、函数名等
  2. 建立上传模型,除了必要的pomGroupId、pomArtifactId、pomVersion等字段,还需要一个order作为模块上传的顺序。
  3. 遍历project里的所有子模块并根据order排序,发现和配置一样的模块名,执行 maven 自带的 uploadArchives 函数,uploadArchives的变量就是我们建立的上传模型。给每个模块新建一个任务,这个任务依赖于 uploadArchives,最后用dependsOn指定任务执行顺序。

项目源码:GradleLearning

版本依赖

每个模块版本上传之后,最终会集成在壳工程里,最简单的壳工程应该只有 application 用来初始化某些东西。其他的都在build.gradle内依赖模块,以本系列的举例:

dependencies {
  implementation 'com.sun.biz:biz_home:1.0.0'
  implementation 'com.sun.biz:biz_me:1.0.0'
  implementation 'com.sun.biz:biz_msg:1.0.0'
  implementation 'com.sun.biz:export_biz_home:1.0.0'
  implementation 'com.sun.biz:export_biz_me:1.0.0'
  implementation 'com.sun.biz:export_biz_msg:1.0.0'
  implementation 'com.sun.fun:fun_share:1.0.0'
  implementation 'com.sun.fun:export_fun_share:1.0.0'
  implementation 'com.sun.module:module_base:1.0.0'
  implementation 'com.sun.module:module_common:1.0.0'
}

各种基础模块、业务模块的接口层和实现层都会依赖,而模块之间依赖则只依赖接口层即可。debug和release可区分snapshot版本。