请点赞关注,你的支持对我意义重大。
Hi,我是小彭。本文已收录到 GitHub · AndroidFamily 中。这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] 带你建立核心竞争力。
小彭今天和群友讨论了一下学习方法的问题,觉得还挺感同身受的。有时候我们遇到不懂的地方,潜意识会产生厌恶和恐惧,大脑会驱使我们去学习和查看这个不懂的地方,结果有可能是陷入到另一个不懂的循环里,忘记了最初的目的。关于系统化学习和碎片化学习,你的想法是怎样的呢?评论区里告诉我吧。
当一个开发者的水平提升到一定程度时,会有由内向外输出价值的需求,包括发布开源项目。而要发布开源组件,则需要将组件发布到公开的远程仓库,如 Jitpack、JenCenter 和 MavenCentral。其中,MavenCentral 是最流行的中央仓库,也是 Gradle 默认使用的仓库之一。
在这篇文章里,我将手把手带你发布组件到 MavenCentral 中央仓库。本文的示例程序使用小彭的开源项目 ModularEventBus 有用请给 Star,谢谢。
这不仅仅是一份攻略,还带着踩过一个个坑留下的泪和挠掉一根根落的宝贵发丝~~~
开发者系列文章:
POM(Project Object Model)指项目对象模型,用于描述项目构件的基本信息。一个有效的 POM 节点中主要包含以下参数:
参数
描述
举例
groupId
组织 / 公司名
io.github.pengxurui
artifactId
组件名
modular-eventbus-annotation
version
组件版本
1.0.0
packaging
格式
jar
在项目中,我们会需要依赖各种各样的二方库或三方库,这些依赖一定会存放在某个位置(Place),这个 “位置” 就叫做仓库。使用仓库可以帮助我们管理项目构件,例如 jar、aar 等等。
主流的构建工具都有 2 个层次的仓库概念:
从这一节开始,我将带你一步步完成发布组件到中央仓库的操作(带你踩坑)。
进入 Sonatype 仪表盘界面,登录或注册新账号:https://issues.sonatype.org:
点击仪表盘面板右上角的 ”新建“ 按钮,按照以下步骤向 Sonotype 提交新建项目的工单:
填写方法总结如下:
io.github.[Github 用户名]
的格式填写,后续步骤中 Sonatype 通过要求我们在个人 Github 仓库中新建指定名称的临时代码库的方式来做身份验证;oss.sonotype.org
,则填写 org.sonotype.oss
。https://github.com/pengxurui/ModularEventBus
;.git
,例如 https://github.com/pengxurui/ModularEventBus.git
。点击弹出的消息进入工单详情页,刚新建的工单要等待 Sonotype 机器人回复,等待大概十几分钟后,在工单底部的评论区会告诉我们怎么操作。
至此,Sonotype 项目准备完毕。
GPG(GNU Privacy Guard) 是基于 OpenPGP 标准实现的加密软件,它提供了对文件的非对称加密和签名验证功能。所有发布到 Maven 仓库的文件都需要进行 GPG 签名,以验证文件的合法性。
安装 GPG 软件有两种方式:
命令行
# 通过 Homebrew 安装 gpg
brew install gpg
如果本地没有 Homebrew 环境则需要先安装,这里也容易踩坑。小彭本地原本就有 Homebrew 环境,但是安装 gpg 的过程中各种报错,最后还是用了最暴力的解法才解决 —— 卸载重装 Homebrew:(
使用 --generate-key
参数,按照指引填写相关信息和 passphrase 私钥口令。另外,使用 --list-keys
参数可以查看当前系统中生成过的密钥。
命令行
# 密钥生成命令
gpg --generate-key
# 密钥查看命令
gpg --list-keys
命令行演示
GPG 在生成密钥对时,会要求开发者做一些随机的举动,以给随机数加入足够多的扰动,稍等片刻就会生成完成了。完成后可以随时使用 —list-keys
参数查看密钥对信息:
命令行演示
解释一下其中的信息:
/Users/pengxurui/.gnupg/pubring.kbx
-----------------------------------
pub ed25519 2022-08-23 [SC] [expires: 2024-08-22]
D8BCD08568BE5D2D634DD99EFD4ECE3B54DE73AA
uid [ultimate] test <test@gmail.com>
sub cv25519 2022-08-23 [E] [expires: 2024-08-22]
# pubring.kbx:本地存储公钥的文件
# 2022-08-23 [SC] [expires: 2024-08-22]:表示密钥对的创建时间和失效时间
# test <test@gmail.com>:用户名和邮箱
# ed25519:表示生成公钥的算法
# cv25519:表示生成私钥的算法
# D8BCD08568BE5D2D634DD99EFD4ECE3B54DE73AA:密钥指纹 / KeyId
至此,你已经在本地生成一串新的密钥对,现在你手上有:
D8BCD08568BE5D2D634DD99EFD4ECE3B54DE73AA
这一串。有时也可以使用较短的格式,取其最后 8 个字符,即 B54DE73AA
这一串;有时候需要删除密钥对,可以使用以下命令:
# 先删除私钥后,才能删除公钥
# 删除私钥
gpg --delete-secret-keys [密钥指纹]
# 删除公钥
gpg --delete-keys [密钥指纹]
密钥对中的公钥信息需要公开,其他人才能拿到公钥来验证你签名的数据,公开的方法就是上传到公钥服务器。公钥服务器是专门储存用户公钥的服务器,并且会用交换机制将数据同步给其它公钥服务器,因此你只要上传到其中一个服务器即可。我最后是上传到 hkp://keyserver.ubuntu.com
服务器的。以下服务器都可以尝试:
pool.sks-keyservers.net
keys.openpgp.org
keyserver.ubuntu.com
pgp.mit.edu
命令行
// 上传公钥
gpg --keyserver 【服务器地址】:11371 --send-keys 【密钥指纹】
// 验证公钥
gpg --keyserver 【服务器地址】:11371 --recv-keys 【密钥指纹】
后文发布组件的时候需要用到密钥口令和私钥文件,可以使用以下参数导出
命令行
# 默认导出到本地目录 /User/[用户名]/
# 导出公钥
gpg --export 【密钥指纹】 > xiaopeng_pub.gpg
# 导出私钥
gpg --export-secret-keys 【密钥指纹】 > xiaopeng_pri.gpg
我在发布组件时遇到 PGPException: unknown public key algorithm encountered
报错,最后排查下来是使用了 Gradle signing 插件不支持 EDDSA 算法,需要使用 RSA 算法。
可以看到上文 3.1 节生成的公钥,可以看到是 ed
开头的,表示使用的是 EDDSA 算法,应该是不同版本中的 --generate-key
参数使用的默认算法不一样。
3.1 节生成的公钥信息
pub ed25519 2022-08-23 [SC] [expires: 2024-08-22]
解决方法是使用 --full-generate-key
参数选择使用 RSA 算法生成密钥对:
命令行演示
至此,密钥对准备完毕。
完成 Sonatype 项目和密钥对的准备工作后,现在着手配置项目的 Gradle 脚本了。Gradle 提供了两个 Maven 插件:
我最初的想法是分别整理出这两个插件的通用脚本,一开始是参考 ARouter 项目里的 publish.gradle 脚本,过程中也遇到各种问题,例如 Javadoc generation failed
,可能是因为 ARouter 是纯 Java 实现的,所以暴露的问题较少。耽搁了一周后,刚好这两天在看 LeakCanary 源码,果然在 LeakCanary 里发现宝藏 —— vanniktech 的发布插件!
报错
Execution failed for task ':eventbus_api:androidJavadocs'.
> Javadoc generation failed. Generated Javadoc options file (useful for troubleshooting): '/Users/pengxurui/workspace/public/ModularEventBus/eventbus_api/build/tmp/androidJavadocs/javadoc.options'
这块脚本是参考 ARouter 项目中 publish.gradle
脚本的,我在此基础上增加了注释和少量改动,如果遇到生成 Javadoc 出现问题,可以把 archives androidJavadocsJar
这一行注释掉。
maven_sonatype.gradle
// 在 ARouter 项目的 publish.gradle 上修改
apply plugin: 'maven'
apply plugin: 'signing'
version = VERSION_NAME
group = GROUP
// 是否 Release 发布(根据是否包含 SNAPSHOT 判断)
def isReleaseBuild() {
return VERSION_NAME.contains("SNAPSHOT") == false
}
// Central Repository: https://central.sonatype.org/publish/publish-guide/
// Release 仓库地址(默认先发布到 staging 暂存库,需要手动发布到中央仓库)
def getReleaseRepositoryUrl() {
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL : "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
}
// Snapshot 仓库地址
def getSnapshotRepositoryUrl() {
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL : "https://s01.oss.sonatype.org/content/repositories/snapshots/"
}
// 仓库账号
def getRepositoryUsername() {
return hasProperty('SONATYPE_NEXUS_USERNAME') ? SONATYPE_NEXUS_USERNAME : ""
}
// 仓库密码
def getRepositoryPassword() {
return hasProperty('SONATYPE_NEXUS_PASSWORD') ? SONATYPE_NEXUS_PASSWORD : ""
}
// 组件配置
def configurePom(pom) {
// 组织名
pom.groupId = GROUP
// 组件名
pom.artifactId = POM_ARTIFACT_ID
// 组件版本
pom.version = VERSION_NAME
pom.project {
// 名称
name POM_NAME
// 发布格式
packaging POM_PACKAGING
// 描述信息
description POM_DESCRIPTION
// 主页
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEV_CONNECTION
}
// Licenses 信息
licenses {
license {
name POM_LICENCE_NAME
url POM_LICENCE_URL
distribution POM_LICENCE_DIST
}
}
// 开发者信息
developers {
developer {
id POM_DEVELOPER_ID
name POM_DEVELOPER_NAME
}
}
}
}
afterEvaluate { project ->
// 配置 Maven 插件的 uploadArchives 任务
uploadArchives {
repositories {
mavenDeployer {
// 配置发布前需要签名
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
// 配置 Release 仓库地址与账号密码
repository(url: getReleaseRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
// 配置 Snapshot 仓库地址与账号密码
snapshotRepository(url: getSnapshotRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
// 配置 POM 信息
configurePom(pom)
}
}
}
// 配置 Maven 本地发布任务
tasks.create("installLocally", Upload) {
configuration = configurations.archives
repositories {
mavenDeployer {
// 本地仓库地址
repository(url: "file://${rootProject.buildDir}/localMaven")
// 配置 POM 信息
configurePom(pom)
}
}
}
// 配置签名参数,部分需要在 local.properties 中配置
signing {
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
if (project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')) {
// Android 类型组件
task install(type: Upload, dependsOn: assemble) { // 依赖于 AGP assemble 任务
repositories.mavenInstaller {
configuration = configurations.archives
configurePom(pom)
}
}
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.source
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
// 生成源码产物
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.source
}
} else {
// 纯 Java / Kotlin 类型组件(如 Gradle 插件、APT 组件)
install {
repositories.mavenInstaller {
configurePom(pom)
}
}
// 生成源码产物
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
// 生成 javadoc 产物
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
}
// Java8 适配
if (JavaVersion.current().isJava8Compatible()) {
allprojects {
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
}
// 配置源码和 Javadoc 发布产物
if (!isReleaseBuild()) {
// 快照版本跳过,提高效率
artifacts {
if (project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')) {
// Android 类型组件
archives androidSourcesJar // 源码
archives androidJavadocsJar // Javadoc,如果报错需要把这一行注释掉
} else {
// 纯 Java / Kotlin 类型组件(如 Gradle 插件、APT 组件)
archives sourcesJar // 源码
archives javadocJar // Javadoc
}
}
}
}
在需要发布的组件里应用这个脚本后,在 gradle.properties
里配置相关参数后就可以发布了。具体可以参考示例程序 ModularEventBus 中被注释掉的参数,也可以参考 ARouter 项目,这里就不展开了,建议用 4.2 节 vanniktech 的发布插件。
项目级 gradle.properties
######################################################################
# for maven_sonatype.gradle
######################################################################
# GROUP=io.github.pengxurui
#
# POM_URL=https://github.com/pengxurui/ModularEventBus/
# POM_SCM_URL=https://github.com/pengxurui/ModularEventBus/
# POM_SCM_CONNECTION=scm:git:git:github.com/pengxurui/ModularEventBus.git
# POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/pengxurui/ModularEventBus.git
#
# POM_LICENCE_NAME=The Apache Software License, Version 2.0
# POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
# POM_LICENCE_DIST=repo
#
# POM_DEVELOPER_ID=pengxurui
# POM_DEVELOPER_NAME=Peng Xurui
#
# SONATYPE_NEXUS_USERNAME=[provide your Sonatype user name]
# SONATYPE_NEXUS_PASSWORD=[provide your Sonatype password]
#
# signing.keyId=[provide you gpg key]
# signing.password=[provide you gpg passphrase]
# signing.secretKeyRingFile=[provide you gpg secret file]
模块级 gradle.properties
######################################################################
# for maven_sonatype.gradle
######################################################################
# POM_NAME=ModularEventBus Annotations
# POM_ARTIFACT_ID=modular-eventbus-annotation
# POM_PACKAGING=jar
# POM_DESCRIPTION=The annotation used in ModularEventBus api
# VERSION_NAME=1.0.0
gradle-maven-publish-plugin ********是一个外国大佬 vanniktech 开源的 Gradle 插件,需要使用 Gradle 7.2.0 以上的 Gradle 环境。它会创建一个 publish Task,支持将 Java、Kotlin 或 Android 组件发布到任何 Maven 仓库,同时也支持发布携带 Java / Kotlin 代码的 Javadoc 产物和 Sources 产物。虽然目前(2022/08/24)这个项目的最新版本只是 0.21.0,不过既然已经在 LeakCanary 上验证过,大胆用起来吧。
以下为配置步骤:在项目级 build.gradle
中添加插件地址,在模块级 build.gradle 中应用插件:
项目级 build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
// vanniktech 发布插件
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0'
// Kotlin Javadoc,非必须
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.6.20"
// 最新版 1.7.10 和 0.21.0 组合有问题,应该是没兼容好。上面两个版本组合我验证过是可以的。
}
}
模块级 build.gradle
apply plugin: "com.vanniktech.maven.publish"
// Kotlin Javadoc,非必须。如果有这个插件,发布时会生成 Javadoc,会延长发布时间。建议在 snapshot 阶段关闭
apply plugin: "org.jetbrains.dokka"
Sync 项目后,插件会为模块增加两个 Task 任务:
~/.m2/repository
。Gradle 面板
分别在项目级 gradle.properties
和模块级 gradle.properties
中配置以下参数:
项目级 gradle.properties
######################################################################
# for vanniktech
######################################################################
# 服务器地址
SONATYPE_HOST=S01
# 发布 release 组件时是否签名
RELEASE_SIGNING_ENABLED=true
# 组织名
GROUP=io.github.pengxurui
# 主页
POM_URL=https://github.com/pengxurui/ModularEventBus/
# 版本控制信息
POM_SCM_URL=https://github.com/pengxurui/ModularEventBus/
POM_SCM_CONNECTION=scm:git:git:github.com/pengxurui/ModularEventBus.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/pengxurui/ModularEventBus.git
# Licenses 信息
POM_LICENSE_NAME=The Apache Software License, Version 2.0
POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENSE_DIST=repo
# 开发者信息
POM_DEVELOPER_ID=pengxurui
POM_DEVELOPER_NAME=Peng Xurui
POM_DEVELOPER_URL=https://github.com/pengxurui/
mavenCentralUsername=[填 Sonatype 账号名]
mavenCentralPassword=[填 Sonatype 密码]
signing.keyId=[密钥指纹,取后 8 位即可]
signing.password=[passphrase 密钥口令]
signing.secretKeyRingFile=[导出的私钥文件路径,如 /Users/pengxurui/xxx.gpg]
模块级 gradle.properties
POM_NAME=ModularEventBus Annotations
POM_ARTIFACT_ID=modular-eventbus-annotation
POM_PACKAGING=jar
POM_DESCRIPTION=The annotation used in ModularEventBus api
VERSION_NAME=1.0.0
特别注意:私有信息不要提交到 git 版本管理中,可以写在 local.properties
中,等到要发布组件时再复制到 gradle.properties
中。而私钥文件也不要保存在当前工程的目录里,可以统一放到工程外的一个目录。
至此,所有准备工作完成。
毕竟发布逻辑都被人家封装在插件里了,有必要知道它背后的工作,浅尝一下。
SonatypeHost.kt
enum class SonatypeHost(
internal val rootUrl: String
) {
DEFAULT("https://oss.sonatype.org"),
S01("https://s01.oss.sonatype.org"),
}
MavenPublishPlugin.kt
private fun Project.defaultJavaDocOption(): JavadocJar? {
return if (plugins.hasPlugin("org.jetbrains.dokka") || plugins.hasPlugin("org.jetbrains.dokka-android")) {
JavadocJar.Dokka(findDokkaTask())
} else {
null
}
}
MavenPublishPlugin.kt
afterEvaluate {
when {
plugins.hasPlugin("org.jetbrains.kotlin.multiplatform") -> {} // Handled above.
plugins.hasPlugin("com.android.library") -> {} // Handled above.
plugins.hasPlugin("java-gradle-plugin") ->
baseExtension.configure(GradlePlugin(defaultJavaDocOption() ?: javadoc()))
plugins.hasPlugin("org.jetbrains.kotlin.jvm") ->
baseExtension.configure(KotlinJvm(defaultJavaDocOption() ?: javadoc()))
plugins.hasPlugin("org.jetbrains.kotlin.js") ->
baseExtension.configure(KotlinJs(defaultJavaDocOption() ?: JavadocJar.Empty()))
plugins.hasPlugin("java-library") ->
baseExtension.configure(JavaLibrary(defaultJavaDocOption() ?: javadoc()))
plugins.hasPlugin("java") ->
baseExtension.configure(JavaLibrary(defaultJavaDocOption() ?: javadoc()))
else -> logger.warn("No compatible plugin found in project $name for publishing")
}
}
终于终于,所有准备和配置工作都完成了!在发布之前,有必要先解释下 Sonatype 中用到的仓库地址:
如果你没有自定义发布的 Maven 仓库,vanniktech 插件默认会发布到 Sonatype 管理的中央仓库中。由于历史原因,Sonatype 中央仓库有 2 个域名:
按照 官方的说法 ,oss.sonatype.org 是过时的,从 2021 年 2 月开始启用 s01.oss.sonatype.org/
截图
官方也会提示目前最新的仓库地址:
截图
细心的朋友会发现官方提供的 snapshot 仓库和 release 仓库的格式不一样,为什么呢?—— 这是因为发布 release 组件是敏感操作,一旦组件发布 release 版本到中央仓库,就永远无法修改或删除这个版本的组件内容(这个规则是出于稳定性和可靠性考虑,如果可以修改,那些本地已经下载过组件的用户就得不到最新内容了)。所以 Sonatype 对发布 snapshot 组件和 release 组件采取了不同策略:
snapshot 组件: 直接发布到 snapshot 中央仓库;
release 组件: 使用 Staging 暂存策略,release 组件需要先发布到暂存库,经过测试验证通过后,再由开发者手动提升到 release 中央仓库。
中央 release 仓库:"https://s01.oss.sonatype.org/content/repositories/releases"
中央 snapshot 仓库:"https://s01.oss.sonatype.org/content/repositories/snapshots"
暂存库:"https://s01.oss.sonatype.org/service/local/staging/deploy/maven2"
vanniktech 插件默认也是按照 Sonatype 的策略走的,浅看一下源码:
MavenPublishBaseExtension.kt
// 暂存库:
if (stagingRepositoryId != null) {
repo.setUrl("${host.rootUrl}/service/local/staging/deployByRepositoryId/$stagingRepositoryId/")
} else {
repo.setUrl("${host.rootUrl}/service/local/staging/deploy/maven2/")
}
// snapshot 库:
if (it.version.toString().endsWith("SNAPSHOT")) {
if (stagingRepositoryId != null) {
throw IllegalArgumentException("Staging repositories are not supported for SNAPSHOT versions.")
}
repo.setUrl("${host.rootUrl}/content/repositories/snapshots/")
}
版本号中带 SNAPSHOT 将被视为 snapshot 组件,会直接发布到 snapshot 中央仓库。经过小彭验证,确实在前端发布后,立马可以在 snapshot 中央仓库搜索到,例如 小彭的组件。
验证截图
版本号中未带 SNAPSHOT 将视为 release 组件,发布 release 组件后,进入 Nexus 面板查看暂存库(右上角 Log in 登录):
操作截图
确认要发布组件后,先点击 Close,再点击 Release 即可发布:
操作截图
Close 的过程会对组件进行验证,验证失败的话就会报错了。你可以直接从 Activity 面板中查看报错提示,我遇到的几次问题都是参数缺失的小问题。
报错提示
点击 Drop 按钮删除有问题的组件:
操作截图
如果验证通过,Release 按钮就会高亮,点击按钮就终于终于发布了。
操作截图
发布成功后,有 3 种方式查看自己的组件:
操作截图
操作截图
操作截图
按照 官方的说法 ,发布后的组件会在 30 分钟内同步到中央仓库,但搜索功能需要达到 4 个小时:
Upon release, your component will be published to Central:
this typically occurs within 30 minutes,
though updates to search can take up to four hours.
怎么依赖大家都懂。讲一下仓库吧,如果是已经发布到 release 中央仓库,你的工程只要包含 mavenCentral()
这个仓库地址就可以了。
示例程序
repositories {
// 中央仓库(不包含 snapshot 中央仓库)
mavenCentral()
// release 中央仓库
maven { url 'https://s01.oss.sonatype.org/content/repositories/releases'}
// snapshot 中央仓库
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'}
// 暂存库,用于验证
maven { url "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2"}
}
Sonatype 账号密码错误:
Failed to publish publication 'maven' to repository 'mavenCentral'
Could not PUT 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/io/github/pengxurui/modular-eventbus-annotation/1.0.2/modular-eventbus-annotation-1.0.2.jar'. Received status code 401 from server: Unauthorized
GPG 密钥错误:
Execution failed for task ':eventbus_annotation:signMavenPublication'.
Error while evaluating property 'signatory' of task ':eventbus_annotation:signMavenPublication'
org.bouncycastle.openpgp.PGPException: checksum mismatch at 0 of 20
GPG 密钥算法错误:
Execution failed for task ':eventbus_annotation:signMavenPublication'.
Error while evaluating property 'signatory' of task ':eventbus_annotation:signMavenPublication'
org.bouncycastle.openpgp.PGPException: unknown public key algorithm encountered
Javadoc 生成报错:
Execution failed for task ':eventbus_api:androidJavadocs'.
Javadoc generation failed. Generated Javadoc options file (useful for troubleshooting): '/Users/pengxurui/workspace/public/ModularEventBus/eventbus_api/build/tmp/androidJavadocs/javadoc.options'
vanniktech 插件与 Dokka 插件兼容问题:
Execution failed for task ':eventbus_api:javaDocReleaseGeneration'.
'void org.jetbrains.dokka.DokkaSourceSetImpl.
(java.lang.String, org.jetbrains.dokka.DokkaSourceSetID,
…
POM 验证错误:
如果你在使用 Sonatype 的过程中遇到任何问题,可以尝试向官方提问。我试过一次,10 分钟后就收到回复了,还是很 Nice 的。
操作截图
操作截图
恭喜,到这里,我们已经能够实现发布开源项目到 MavenCentral 中央仓库。还没完,引出两个问题:
关注我,带你了解更多。
你的点赞对我意义重大!微信搜索公众号 [彭旭锐],希望大家可以一起讨论技术,找到志同道合的朋友,我们下次见!
手机扫一扫
移动阅读更方便
你可能感兴趣的文章