gradle工程maven部署经验总结
前言
若使用gradle进行项目的开发,在引入一些sdk和开发组件时,依赖配置中经常会有类似于implementation 'androidx.appcompat:appcompat:1.2.0'的语句,gradle就可以根据引号内的内容去配置好的仓库中找到你想使用的jar包或是aar包。
上述的内容格式可以视为groupId:artifactId:version,这是maven仓库用于唯一定位一个包的索引,在进行组件或者sdk开发时,如果想将代码进行发布供他人使用,只需使用相应的上传工具并指定用于索引所必要的属性,就可以完成发布。
maven上传插件
对于Android开发来说,可部署的代码包格式,除了jar还有aar,aar的生成依赖于Android Gradle Plugin,在AGP 3.6.0以下,只能使用maven插件。
1 | apply plugin: 'maven' |
通过如上的配置就可以生成对应task,运行
1 | ./gradlew [moduleName:]uploadArchives |
执行完毕之后就可以找到部署到指定仓库的代码包。
如果目标仓库需要身份认证,有两种方式可以处理
- 使用authentication
1
2
3repository(url: "scp://repos.mycompany.com/releases") {
authentication(userName: "me", password: "myPassword")
} - 在仓库地址之前加上认证信息,用@符号和地址分割
1
repository(url: "scp://me:myPassword@repos.mycompany.com/releases")
AGP variant
maven插件在AGP下使用会有一些问题,插件不支持agp的variant,会默认将configuration archive下的代码包进行发布,也就是说,默认会发布release buildType的构建结果。一旦module声明了productFlavors,配置了新的variant,maven插件就无法部署了,需要额外进行一些处理,通过如下代码,可以选择指定名称的variant进行构建与发布。
1 | android.libraryVariants.all { variant -> |
需要注意的是,通过这样的方式发布的aar,其对应的pom文件没有对应的依赖选项,需要手动填充Conf2ScopeMappings。但是aar又不支持直接在MavenPluginConvention内的conf2ScopeMappings中进行操作。目前依笔者经验,比较可行的方案是在pom配置完成后进行处理。dependencies内的element为org.apache.maven.model.Dependency,在脚本中无法直接引用,需要通过反射操作。
1 | deployer.pom.whenConfigured { pom -> |
maven-publish插件
在AGP 3.6.0版本以后,添加了对maven-publish的支持,下面是官方的例子
1 | afterEvaluate { |
要注意的是该配置必须写在afterEvaluate中,因为AGP的配置也是在gradle默认配置阶段结束后,运行阶段之前进行的。
如果要指定部署的仓库,可以按照如下方式(仓库的声明方式和maven插件相同)
1 | publishing { |
如果不配置repositorymaven-publish对每一个配置完成的publication和Repository进行组合,并为其生成task
1 | publishDebugPublicationToMavenLocal |
*ToMaven是默认生成的上传任务,会将包部署至USER_HOME/.m2/repository下。maven-publish插件相比旧版本的maven插件,配置的灵活性更高。
多project上传
在开发sdk时,经常会出现多个module同时开发的情况,module之间有依赖关系,且可能运行在不同的环境下。我见过很多开发者,选择将一个module部署在本地,或使用SNAPSHOT部署在maven服务器上,每次改动一个module,就重新部署一遍,这无疑是极其影响开发效率的。
究其原因,发现直接使用implementation project的方式引用一个module,在上传时,pom文件内对应的依赖项无法指定group和version。实际上这个问题很好解决,只需要在对应module的build.gradle中指定group和version即可,artifactId使用的是module name。
如果想指定artifactId,却不能修改已有的module name,并且使用的AGP版本在3.6.0以上(gradle 6.0以上),这时可以考虑使用dependencySubstitution。
1 | configurations.all { |
首先使用[groupId:artifactId:version]的形式引入依赖,此时并不需要这个依赖已经存在;之后将上述代码添加到build.gradle中dependencies闭包的上面。此时gradle会用依赖替换原则,将标识定位的模块替换成本地的module,开发也和直接implementation project完全相同。
至于gradle 6.0以下的情况,由于dependencySubstitution不支持gradle api的依赖引用方式,因此该方案有很大的缺陷;不过可以考虑使用上文提到的方式,在pom.whenConfigured的回调中,直接进行pom依赖项的处理。