最近发现在我们项目中使用implementation "cn.soul.android.lib:cpnt-login:1.0.9" 依赖下来的是cpnt-login:1.0.9@jar,而不是cpnt-login:1.0.9@aar,下面分析下原因
一:理解pom的packaging节点
先看一个gradle中典型的uploadArchives配置
uploadArchives {
repositories {
mavenDeployer {
repository(url: uri("../repo/"))
pom.project {
version '1.0.9'
artifactId 'cpnt-login'
groupId 'cn.soul.android.app'
packaging 'aar'
description 'DESCRIPTION'
}
}
}
}
执行./gradlew cpnt-login:uploadComponent(声明下,我们项目中uploadComponent其实就是uploadArchives的扩展,继承自Upload,做了一点额外配置,而且会上传jar)后得到pom文件内容:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.soul.android.app</groupId>
<artifactId>cpnt-login</artifactId>
<version>1.0.9</version>
<description>DESCRIPTION</description>
<dependencies>
...
</dependencies>
</project>
可以看到packaging节点没了...看了看maven上一些别的aar包对应的pom文件都有<packaging>aar</packaging>节点,那为什么cpnt-login的pom文件没有这个节点呢?
看一眼cpnt-login包的内容
可见cpnt包中多了一个jar,这个jar是我们故意加入的,其中包含了此aar组件向外暴露的接口。
参考: maven.apache.org/pom.html 中一段介绍:“When no packaging is declared, Maven assumes the packaging is the default: jar”, 可以得出结论:
1 执行uploadArchives上传jar包时,若没有特殊配置(由下文可知指没有配置Classifier),产生的pom文件不加packaging节点。
2 maven依赖的时候若发现pom文件没有packaging节点,默认就会认为pom文件最终指向的是个jar包。
二:分析pom的packaging节点产生过程
ok,现在maven的packaging节点已经理解了,那么对于我们这个cpnt-login组件里面既有aar文件也有jar文件,uploadArchives产生的pom文件为啥偏偏选择了jar没选择aar呢,分析这个就得调试uploadArchives这个task了,对应Upload这个类 全局搜索下uploadArchives,断点DefaultArtifactPom-addArtifact()方法
public void addArtifact(Artifact artifact, File src) {
throwExceptionIfArtifactOrSrcIsNull(artifact, src);
PublishArtifact publishArtifact = new MavenArtifact(artifact, src);
ArtifactKey artifactKey = new ArtifactKey(publishArtifact);
if (this.artifacts.containsKey(artifactKey)) {
throw new InvalidUserDataException(String.format("A POM cannot have multiple artifacts with the same type and classifier. Already have %s, trying to add %s.", this.artifacts.get(
artifactKey), publishArtifact));
}
if (publishArtifact.getClassifier() != null) {
addArtifact(publishArtifact);
assignArtifactValuesToPom(artifact, pom, false);
return;
}
if (this.artifact != null) {
// Choose the 'main' artifact based on its type.
if (!PACKAGING_TYPES.contains(artifact.getType())) {
addArtifact(publishArtifact);
return;
}
if (PACKAGING_TYPES.contains(this.artifact.getType())) {
throw new InvalidUserDataException("A POM can not have multiple main artifacts. " + "Already have " + this.artifact + ", trying to add " + publishArtifact);
}
addArtifact(this.artifact);
}
this.artifact = publishArtifact;
this.artifacts.put(artifactKey, publishArtifact);
assignArtifactValuesToPom(artifact, pom, true);
}
我们没有配置Classifier,这里只会走最后一行的assignArtifactValuesToPom方法
private void assignArtifactValuesToPom(Artifact artifact, MavenPom pom, boolean setType) {
if (pom.getGroupId().equals(MavenProject.EMPTY_PROJECT_GROUP_ID)) {
pom.setGroupId(artifact.getModuleRevisionId().getOrganisation());
}
if (pom.getArtifactId().equals(MavenProject.EMPTY_PROJECT_ARTIFACT_ID)) {
pom.setArtifactId(artifact.getName());
}
if (pom.getVersion().equals(MavenProject.EMPTY_PROJECT_VERSION)) {
pom.setVersion(artifact.getModuleRevisionId().getRevision());
}
if (setType) {
pom.setPackaging(artifact.getType());
}
}
调试发现这个方法走了两遍,artifact参数第一步指向的是cpnt-login.aar,第二步指向的是cpnt-login.jar,第二步覆盖了第一步的结果,导致了最终packaging选择了jar类型,(外面有个for循环,列表的顺序是jar产物在aar产物后面,要理解列表添加顺序,让aar在后面可以解决此问题,这涉及到控制产物目录添加顺序问题),且因为外面没有配置Classifier,外面写的packaging 'aar'其实被artifact.getType()覆盖了。。。
简单粗暴,使用pom.withXml方法直接在pom中编辑packaging节点
uploadArchives {
repositories {
mavenDeployer {
repository(url: uri("../repo/"))
pom.project {
version '1.0.15'
artifactId 'cpnt-login'
groupId 'cn.soul.android.app'
packaging 'aar'
description 'DESCRIPTION'
}
pom.withXml {
asNode().appendNode('packaging', 'aar')
}
}
}
}
解决~