一、注册sonatype账号
我们写的一些开源库(jar、aar等),发布到开源仓库,其他开发者通过一行代码就能使用。目前jcenter要关闭了,我们写的开源库可以发布到中央仓库MavenCenteral。发布到中央仓库MavenCentral,需要注册sonatype账号。
1、填写信息,注册sonatype账号
打开sonatype官网:issues.sonatype.org/
打开注册界面,填写注册信息:
- Email:邮箱账号,接收sonatype推送的邮件
- Full name:账号名,按照自己喜欢随便填
- Username:账号,登录sonatype和MavenCentral的账号
- Password:密码
点击sign up账号就注册成功了。然后会让你设置一下账号头像,这里就不截图了。
2、新建issue工单
点击新建
填写新建信息:
可以参考图片上的示例填写:
- 项目:Community Support - Open Source Project Repository Hosting (OSSRH)
- 问题类型:New Project
- 概要:随便填写,不重要
- groupId:项目组织唯一的标识符。推荐个人用github账号,格式:io.github.xxxx,xxxx是你的GitHub账号路径,比如我的github主页是:github.com/jinxiyang, xxxx就是jinxiyang。也可以自建服务器,自定义路径。goupId不能随便乱填,后面sonatype会校验你是否拥有此域名。
- Project URL:项目地址,可以填GitHub上的项目地址,如:github.com/jinxiyang/O…
- SCM url:版本仓库的拉取地址,可以填GitHub上的项目地址加
.git,如:github.com/jinxiyang/O… - Alread Synced to Central:选NO,我们还没有打包aar,没有上传到中央仓库
点击右下角新建,就创建了一个issue工单,进入了这个issue详情页,大概10分钟左右,会收到comment,让我们验证是否拥有填写groupId对应的域名。我们的邮箱也会收到邮件。
3、验证groupId
多刷新这个issue工单详情页,大概10分钟左右,会收到comment,让我们验证是否拥有填写groupId对应的域名。我们的邮箱也会收到邮件。
填写的groupId:
- 如果是:com.baidu.xxxx,就需要验证我们是否拥有域名:www.baidu.com ,对应的是自建服务器
- 如果是:io.github.xxxx,需要我们在GitHub新建指定名称的临时空项目
- 第一步,在GitHub新建指定名称的项目,如:github.com/jinxiyang/O…
- 第二步,点击issue详情页的Respond按钮,告诉sonatype官方,可以验证groupId了
几分钟后我们会收到一条comment,邮箱也会收到邮件,告诉我们groupId验证通过,我们可以上传我们的库(jar、aar)到中央仓库MavenCentral了。
我们可以打开网址:central.sonatype.org/publish/pub… ,查看仓库地址,后面发布时会用到。
snapshot仓库上传地址:
https://s01.oss.sonatype.org/content/repositories/snapshots/
release仓库上传地址:
https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
至此sonatype账号注册完成了。
二、生成GPG签名秘钥和文件
发布到中央仓库的文件,需要签名,我们需要安装gpg,并生成秘钥,然后导出秘钥文件。
1、安装Homebrew
安装GPG,需要先安装Homebrew。安装Homebrew,踩了不少坑,可以看我的这篇文章:
最后发现,用国内大神的脚本,轻轻松松几分钟就装好了,传送门:
zhuanlan.zhihu.com/p/111014448
MacOS、Linux、Windows都支持安装。
2、安装GPG并生成秘钥
在terminal中输入命令,安装gpg:
brew install -v gpg
安装成功之后,使用gpg命令,生成秘钥:
gpg --generate-key
期间会要求输入:真实姓名、电子邮件地址、设置秘钥密码,按照提示一步一步操作:
秘钥的密码要记住,后面会用到。keyId是秘钥的后8位,后面也会用到。
把这个公钥(图片上打码的长串)上传到服务器,往这三个服务器上传,有一个成功就可以了:
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys 24B6CXXXXXXXXXXXXXXXXXXXXXXXXXX00BA0DDDA
gpg --keyserver hkp://keys.openpgp.org:11371 --send-keys 24B6CXXXXXXXXXXXXXXXXXXXXXXXXXX00BA0DDDA
gpg --keyserver hkp://pool.sks-keyservers.net:11371 --send-keys 24B6CXXXXXXXXXXXXXXXXXXXXXXXXXX00BA0DDDA
验证是否上传成功了,和上面命令对应:
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys 24B6CXXXXXXXXXXXXXXXXXXXXXXXXXX00BA0DDDA
gpg --keyserver hkp://keys.openpgp.org:11371 --recv-keys 24B6CXXXXXXXXXXXXXXXXXXXXXXXXXX00BA0DDDA
gpg --keyserver hkp://pool.sks-keyservers.net:11371 --recv-keys 24B6CXXXXXXXXXXXXXXXXXXXXXXXXXX00BA0DDDA
导出签名文件,后面发布aar用到。命令:
gpg --export-secret-keys -o my.gpg
在你的电脑的根目录下,会生成一个文件my.gpg,我的文件的路径:
/Users/jinxiyang/my.gpg
三、编写发布aar到maven脚本
1、配置gradle.properties文件
#maveCentral账号密码
sonatypeUsername=yangjinxi
sonatypePassword=xxxxxxxx
#秘钥的后8位
signing.keyId=0BA0DDDA
signing.password=xxxxxxxx
signing.secretKeyRingFile=/Users/jinxiyang/my.gpg
这些配置,建议写在local.properties文件,发布aar时,从local.properties复制到gradle.properties,避免代码上传到GitHub泄漏密码。平时gradle.properties里的都是空值。
2、编写发布aar脚本文件
工程下新建文件uploadMavenCentral.gradle。
以下是uploadMavenCentral.gradle内容和相关注释:
//引入maven-publish和签名插件
apply plugin: 'maven-publish'
apply plugin: 'signing'
//发布aar的版本号,有-SNAPSHOT代表发布snapshot,没有则发release
def libVersion='0.1.3'
//def libVersion='0.1.3-SNAPSHOT'
task androidSourcesJar(type: Jar) {
archiveClassifier.set("sources")
// 源码路径,包含Java、kotlin代码
from android.sourceSets.main.java.getSrcDirs()
exclude "**/R.class"
exclude "**/BuildConfig.class"
}
publishing {
publications {
//这里的maven是闭包名,可以随便定义的,也可以叫aar、release等等
maven(MavenPublication) {
// group id,发布后引用的依赖的 group id
groupId 'io.github.jinxiyang'
// 发布后引用的依赖的 artifact id
artifactId 'overscrolllayout'
// 发布的版本
version libVersion
// 发布的aar,依赖bundleReleaseAar task,module要先构建出aar
afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) }
//发布的源码文件,从上面定义的task androidSourcesJar获取
artifact androidSourcesJar
pom {
// 构件名称,可以自定义
name = 'OverScrollLayout'
// 构件描述
description = 'Android自定义控件,支持RecyclerView、NestedScrollView过度滚动并回弹'
// 构件主页
url = 'https://github.com/jinxiyang/OverScrollLayout'
// 许可证名称和地址
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
// 开发者信息
developers {
developer {
name = 'yangjinxi'
email = '1137501600@qq.com'
}
}
// 版本控制仓库地址
scm {
url = 'https://github.com/jinxiyang/OverScrollLayout'
connection = 'scm:git:github.com/jinxiyang/OverScrollLayout.git'
developerConnection = 'scm:git:ssh://git@github.com/jinxiyang/OverScrollLayout.git'
}
}
// pom文件中声明依赖,从而传递到使用方
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.implementation.allDependencies.each {
// 避免出现空节点或 artifactId=unspecified 的节点
if (it.group != null && (it.name != null && "unspecified" != it.name) && it.version != null) {
println "dependency=${it.toString()}"
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'implementation')
}
}
}
}
}
repositories {
maven {
// 发布的仓库地址,这里根据发布的版本区分了release和snapshot版本两种情况
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
url = libVersion.endsWith('-SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
// 这里就是之前在 issues.sonatype.org 注册的账号
username sonatypeUsername
password sonatypePassword
}
}
}
}
//签名
signing {
sign publishing.publications
}
3、库module引入发布脚本
在我们的库module引入发布脚本 uploadMavenCentral.gradle
apply from: '../uploadMavenCentral.gradle'
四、发布aar到仓库
1、点击task,发布aar
配置后发布脚本后,同步项目,在Android Studio的右边栏,点击Gradle,如下图:
-
我们可以点击红框中的
publish或者publishMavenPublicationToMavenResposity,发布aar到中央仓库MavenCentral -
我们可以点击红框中的
publishToMavenLocal或者publishMavenPublicationToMavenLocal,发布aar到本地仓库
本地仓库的地址,格式:~/.m2/repository,比如我的:
/Users/jinxiyang/.m2/repository
publishMavenPublicationToMavenResposity 和 publishMavenPublicationToMavenLocal 这个task名称中的第一maven,是我们定义的闭包名,如果我们定义的闭包名是:aar,则:
2、terminal执行命令,发布aar
在工程的terminal下,执行命令:
./gradlew :<moduleName>:<taskName>
如下:
//发布到中央仓库mavenCentral
./gradlew :overscrolllayout:publish
//发布aar到本地仓库
./gradlew :overscrolllayout:publishToMavenLocal
如果遇到terminal报错:
这是因为terminal在执行命令时,构建工具gradle用到了Java,调用了系统的Java,系统的Java版本是Java8,但我们需要用Java11。
在gradle.properties文件配置变量org.gradle.java.home为Java11的路径就可以了。
org.gradle.java.home=/Applications/Android Studio.app/Contents/jre/Contents/Home
具体的地址,可以看Android Studio的Preferences
五、查看和使用中央仓库MavenCentral的aar
aar已经发布出去了,到底有没有成功?如何查看呢?
打开网址:s01.oss.sonatype.org/ ,输入账号名与密码,就是我们前面注册的sonatype账号。
在上面第三步,编写发布aar脚本中,我们脚本配置的仓库地址是:
repositories {
maven {
// 发布的仓库地址,这里根据发布的版本区分了release和snapshot版本两种情况
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
...
}
}
release和snapshot仓库地址,有很大不同的,其实release仓库地址可以下面这样配置,这样两个仓库地址就相似了:
repositories {
maven {
// 发布的仓库地址,这里根据发布的版本区分了release和snapshot版本两种情况
def releasesRepoUrl = "https://s01.oss.sonatype.org/content/repositories/releases"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
...
}
}
具体的区别后面详细介绍。
1、暂存库Staging Reposities
我们发布release aar时,如果用的是这个地址:
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
aar将会被发布到暂存库Staging Reposities,如下图,可以看到我们发布的aar:
暂存库Staging Reposities,从名称上就能看出来,Staging:正在登台,暂存的意思。
那暂存库里aar如何登台呢?也就是如何发布到中央仓库呢?
根据官方提供的相关文档:# Managing Staging Repositories,以下步骤:
- 选中我们发布的暂存仓库,
io.github.jinxiyang-1001, 随着以后发布次数越多,后面四位数字越来越大 - 点击close
- 点击release
如下:
close的弹窗,点击confirm
close动作会执行一系列校验,没问题后,release按钮就亮起来了
点击release按钮,默认勾上drop,表示发布成功之后,自动删除暂存库,如图:
自动drop后,暂存库就没有了,我们的aar就被发布到了Repositories的Releases。
讲了这么多,都是release aar的发布,而snapshot aar则直接被Repositories的Snapshots。
反应快的小伙伴,已经知道原因了,是因为我们发布脚本填的仓库地址:
repositories {
maven {
// release 先发布到 Staging Repositories 暂存库
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
// release 直接发布到 Repositories的Releases,个人开发者可以直接用这个仓库地址
def releasesRepoUrl = "https://s01.oss.sonatype.org/content/repositories/releases"
// snapshot 直接发布到 Repositories的Snapshots
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
...
}
}
为什么要弄个暂存库Staging Repositories?这么麻烦
当项目很大时,不只一个人开发,开源库也是,最后真正发布之前,需要多次修改和层层测试,有问题打回来修改,然后再提交一个版本,再测试,再打回,……,最后没问题了,aar从暂存库发布到release,到了中央仓库MavenCentral。个人开发者可以直接发布到release仓库地址,不用暂存库。
官方提供的暂存库管理文档:# Managing Staging Repositories
2、仓库Repositories
在仓库Repositories中,查看发布的release/snapshot aar,可以实时看到:
-
Releases:release仓库,仓库地址:
https://s01.oss.sonatype.org/content/repositories/releases -
Snapshots:snapshot仓库库,仓库地址:
https://s01.oss.sonatype.org/content/repositories/snapshots/
如果我们是第一次发布库到maven,这时在我们issue的工单详情页,会收到sonatype官方一条comment:
官方告诉我们,这个io.github.jinxiyang已经激活了,过4个小时就能搜索到我们库了,就能引用库。
据我实践,可能不只4个小时,7个小时以上也可能,真苦逼!
如果等了很久,在MavenCentral上就是出不来,可以在sonatype上提issue工单,请求官方支持。文章第六部分,有提工单请求帮助的示例,可以参考。
3、官方方式使用开源库
经历了千难万苦,等待了好长时间(7小时以上),库终于可以用了。
在项目build.gradle,依赖mavenCentral,Android默认有了
buildscript {
repositories {
mavenCentral()
....
}
....
}
实际只需要一行代码,在主工程中添加依赖库:
implementation 'io.github.jinxiyang:overscrolllayout:0.1.1'
4、立即使用开源库
有没有办法,发布之后提前使用了,答案是当然有。
在项目根目录下的build.gradle,配置maven地址为上面Releases的地址,snapshot配置类似:
buildscript {
repositories {
mavenCentral()
google()
maven {
//release仓库地址
url 'https://s01.oss.sonatype.org/content/repositories/releases'
//snapshot仓库地址
//url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.1'
}
}
//注意allprojects有的项目是在setting.gralde中配置的
allprojects {
repositories {
mavenCentral()
google()
maven {
//release仓库地址
url 'https://s01.oss.sonatype.org/content/repositories/releases'
//snapshot仓库地址
// url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
5、本地仓库mavenLocal的使用
在实际生成中,我们常常发布到本地maven仓库,来开发测试,简单又方便,没问题在发布到mavenCentral。怎么使用本地仓库呢?
在第四章节:发布aar到maven,提到发布aar到本地, publishToMavenLocal 或者 publishMavenPublicationToMavenLocal,发布aar到本地仓库。
在build.gradle加入本地仓库:mavenLoca(),如下:
buildscript {
repositories {
//本地maven仓库,本地仓库的地址,`~/.m2/repository`
mavenLoca()
...
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.1'
}
}
//注意allprojects有的项目是在setting.gralde中配置的
allprojects {
repositories {
mavenLoca()
...
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
6、在sonatype查看我们的库
千难万险已经过去了,如何高大又时尚的分享我们的开源库呢?
打开网址:search.maven.org/ ,查找我们的库:
六、提issue工单,请求官方帮助
如果按照本文一步一步操作,还是无法以mavenCentral()同步下来aar,可以在sonatype提Publish Support工单,请求帮助查找原因。
如:
sonatype帮我同步了一下,问题解决了:
七、本文示例代码GitHub
Android自定义控件,支持RecyclerView、NestedScrollView过度滚动并回弹
八、致谢
发布aar到mavenCentral,从零开始,踩了不少坑,参考了不少文章,在这里特别感谢!如有错误请大家多多留言!
# 建议收藏,从 jCenter 迁移到 MavenCentral 完整方案