最近重构项目,项目中有很多模块会提供给第三方使用。以前的做法是将所用模块打成一个本地aar 包给使用方使用。随着接入方的增加,就会有不同的需求,比如有些接入方只使用模块A,其他模块不再使用。于是在这次重构中,也需要考虑如何让接入方只接入需要的模块???
我们的解决方案是:将所有的模块都生成了 maven 的形式,提供给第三方调用。
优点:
1. 接入灵活且包最小化
2. 解决多模块之间共同依赖的冲突问题
本篇主要解决maven三个场景的发布配置:
- 多模块下的配置
- 多渠道下的配置
- 多模块多渠道一个按键自动化发布
maven-publish插件的基本用法:
A. 项目根目录创建文件:local-aar.gradle ,内容如下:
apply plugin: 'maven-publish'
task sourceJar(type: Jar) {
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}
afterEvaluate {
publishing {
publications {
// studyMaven 可以自定义名字
studyMaven(MavenPublication) {
// maven格式:com.example.maventest:common:1.1.0-SNAPSHOT
groupId = "com.example.maventest"
artifactId = "common"
version = "1.1.0-SNAPSHOT"
// components.all包含了 debug、release
from components.release
// 如果要同时生成jar包,可使用下面注释
// artifact sourceJar
}
}
repositories {
maven {
allowInsecureProtocol = true
url = "上传的maven地址"
credentials {
username = "123456"
password = "123456"
}
}
}
}
}
B. 创建需要上传maven 的 common模块
在build.gradle(common) 中引用配置:
apply from: “${rootProject.rootDir}/local-aar.gradle”
就可以看到下图信息publishing
我们常用的publish 和 publishToMavenLocal
publish : 发布到线上
publishToMavenLocal: 发布到本地,默认存放在 ~\Users\ .m2\repository下
上面最基本的写法。我们将以此为模板不断的扩充,已满足不同的场景
下面以本地maven为例,完成各个场景的需求
1. 多模块下的配置
解决的需求:如何用一份 local-aar.gradle文件,配置多个模块???
A. 创建一个新模块router
router的build.gradle 都引用如下配置
apply from: “${rootProject.rootDir}/local-aar.gradle”
这样common 和 router 两个模块maven上传功能了。每个模块可以用相同的包名,但是artifactId 和 version 不同。
所以我们可以让这些变量变成模块自定义的属性
B. 根目录下创建ext.gradle文件,内容如下
project.ext {
arr_build_boolean = true // maven发布控制
aar_groupId = "com.example.maventest"
aar_artifactId = project.name // 获取模块名字 common
arr_version = '1.1.0-SNAPSHOT'//测试版本号:0.0.3-SNAPSHOT 正式版本号:0.0.3
}
然后修改local-aar.gradle 文件内容:
差异性设置:
common 的 build.gradle:
验证结果:点击publishToMavenLocal
2. 多渠道下的配置
往往一个模块会有多个渠道,下面定义增加一个渠道,满足内外销的区分
A. 项目根目录创建config.gradle
config.gradle
android {
flavorDimensions "region"
productFlavors {
domestic {
dimension "region"
}
export {
dimension "region"
}
}
sourceSets{
domestic.setRoot('build-types/release')
export.setRoot('build-types/releaseExp')
domestic.java.srcDirs = ['build-types/release/src']
export.java.srcDirs = ['build-types/releaseExp/src']
}
}
B. common和router引用config.gradle
apply from: “${rootProject.rootDir}/ext.gradle”
然后就会报如下问题:
Script 'E:\project\MavenTest\local-aar.gradle' line: 19
* What went wrong:
A problem occurred configuring project ':common'.
> Could not get unknown property 'release' for SoftwareComponentInternal set of type org.gradle.api.internal.component.DefaultSoftwareComponentContainer.
这是因为我们添加了新的渠道后, components.getNames() 中不在是debug 和 release .
我们可以打印看一下:
所以我们可以将其修改为:
from components.domesticRelease
这样就不会报错了。 但是这样很不方便,如果想生成其他的maven 还要手动改代码。这肯定不能忍受。
于是修改了下面代码:
这样你想生成那个渠道的maven 都可以。验证一下,点击 publishExportReleasePublicationToMavenLocal验证一下:
一般情况下我们不需要生成debug版本的渠道maven,再次修改后的完整配置如下:
apply plugin: 'maven-publish'
apply from: "${rootProject.rootDir}/ext.gradle"
task sourceJar(type: Jar) {
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}
afterEvaluate {
publishing {
publications {
def componentNameList = components.getNames()
componentNameList.forEach { componentName ->
def artifactName = null
if ("release" == componentName) {
artifactName = project.ext.aar_artifactId
} else if (componentName.contains("Release")) {
if (componentName.contains("export")) {
artifactName = project.ext.aar_artifactId + "-export"
} else {
artifactName = project.ext.aar_artifactId + "-domestic"
}
}
if (artifactName != null) {
"$componentName"(MavenPublication) {
groupId = project.ext.aar_groupId //组id
artifactId = artifactName //具体的项目id
version = project.ext.arr_version //版本号
// release、domesticRelease、exportRelease
from components.getByName(componentName)
// 运行任务,把源码打进去
// artifact sourceJar
}
}
}
}
repositories {
maven {
// publish --- 上传服务器配置:
allowInsecureProtocol = true
url = "https://www.xxxx.com"
credentials {
username = "swdp"
password = "swdp"
}
}
}
}
}
点击publishToMavenLocal验证下:
ok ,到这里我们就能支持多模块,且多渠道 生成maven了。 本想说再见,但是总会有改不完的需求。
3. 多模块多渠道一个按键自动化发布
需求是这样的:router 模块依赖了 common模块,如果每次要构建 router的maven,就一定要先构建出common的maven. (即common先构建maven 后 router 才能构建maven.)
环境配置:
在router的build.gradle 中配置如下依赖:
// 注意一定要用exportImplementation 处理common的外销, 内销可以用domesticImplementation
exportImplementation "com.example.maventest:common-export:1.2.0-SNAPSHOT"
setting.gradle 中添加下图红框部分:
点击router的publishToMavenLocal,验证:
可以去router-domestic和router-export目录下看pom文件内容,可以发现router-domestic不会依赖common,而router-export会依赖common
回到我们的需求:router的构建需要依赖common的构建。如果这样的依赖模块有很多,我们每一次构建模块不就会很复杂,而且要点击publish多次。在尝试了很多方法后,我这里给出一个解决方法:用shell 命令执行 “gradle publishToMavenLocal”. 这样就能搞定我们的需求。
环境配置:
A. gradle 环境配置:https://blog.youkuaiyun.com/sysocc/article/details/123202398
Terminal 验证:
B. 根目录创建 order-publish.gradle 配置
apply from: "${rootProject.rootDir}/ext.gradle"
// 需要配置全局gradle和java11 环境
if (project.ext.arr_build_boolean) {
task allPublishToMavenLocal(type: Exec) {
setGroup("private")
println("> Task :allPublishToMavenLocal")
def cmd = buildShell("publishToMavenLocal")
commandLine 'sh', '-c', cmd
}
task allPublish(type: Exec) {
setGroup("private")
println("> Task :allPublish")
def cmd = buildShell("publish")
commandLine 'sh', '-c', cmd
}
}
static String buildShell(String type) {
def shellContent = new StringBuilder()
String[] moduleNameList = new String[]{
"common"
}
for (String moduleName : moduleNameList) {
shellContent.append("cd ./$moduleName && gradle $type && cd .. &&")
}
shellContent.append("gradle $type")
return shellContent.toString()
}
C.根目录build.gradle
然后就可以看到下图按键:
allPublish:所用maven上传到线上
allPublishToMavenLocal: 所用maven上传到本地
点击 allPublishToMavenLocal,执行失败:
gradle版本太高,切换一下:
再次点击 allPublishToMavenLocal:
终于可以下班回家了。。。