背景
以前我们 Android 开发引用的第三方库都是通过jcenter()
库依赖来的,很多库也是发布在上面的,包括我们公司的的。但是最近jcenter
已经跑路了!这个是新闻链接,大致意思是说2021年3月31号之后就不能提交新的库了,旧的库2022年2月1号还可以提供下载,之后旧不能了。所以项目中用jcenter()
依赖的库,之后就很有可能就编译不成功了,不巧的是据大部分项目都是依赖的jcenter()
,因为是Google默认的。
计划
既然jcenter()
跑路了,那我们就换一个,mavenCentral()
就是我们今天要讲的。这个仓库也是一直存在的,目前一些比较大的库例如:retrofit
、glide
等等都已经转移到这个上面了。但是这个仓库上传的准备工作及其麻烦,真的是费了我九牛二虎之力去研究,网上很多资料都过时了,填了好多坑终于搞定了,现在把步骤写下来做个备份,也给其他人一个参考。
注册
Sonatype 账户
mavenCentral
仓库是属于 Sonatype 管理的,我们需要注册一个他们家的账号 -> 网址
注册完了,登录后回让你选择一个工作:
这里我们选择Create an issue
然后我们选择Community Support — Open Source Project Repository Hosting
和New Project
Group Id:
再填下面东西之前,我们先看上面的图了解下什么是GROUP_ID
、ARTIFACT_ID
、VERSION
,其中GROUP_ID
比较重要,我们等下要填的。Sonatype 管理比较严,这是他们的要求,英文好的仔细看看。如果你的GROUP_ID
填的格式着这种公司的名字像:com.tencent.mm.opensdk
他后面审核的时候会要求你证明tencent.com
这个域名是属于你的。
对于一般个人开发者可能你并没有相应的域名,又或者你们公司域名不归你管理,这种认证就比较麻烦。我就属于这种,所以我们退而求其次,只能把GROUP_ID
填成github
的这种形式,像这样com.github.xxxx
。这个xxx
还必须是你的GitHub
的username
:
像Glide
的GROUP_ID
就是com.github.bumptech.glide
。当然你按照他们的要求来会审核会比较块,实在有特殊情况你就得和他们得审核人员掰扯掰扯了,也不是不可以。我英语不好懒得掰扯,就把我之前用的GROUP_ID
给换掉了,反正也没人用🤣~
后面的ARTIFACT_ID
、VERSION
是可随意。
Create
其他的就比较好理解了,照着要求填就是了
- Summary: 说明下你要来干嘛
- Description: 说明下你要来干嘛
- Group Id: 你的 group ID,
- Project URL: 项目的URL
- SCM url: 代码的URL,一般写git的链接
认证
填完了一会之后会看到下面有人评论你的Issue
应该是要求你去GitHub
建立一个他要求的repo
,按照他的要求建完了之后,回复他,然后他再验证。等你们掰扯完了之后他就会告诉你,你的GROUP_ID
准备好了,你可以去提交项目了,那么恭喜了第一步完成了。
密钥
在提交你的包的时候他们还要求有个加密验证,没搞懂是干嘛的,反正照着做就完了...
安装GnuPG
去官网下载一个你操作系统的你的安装包,我是Windows 10,下载的是这个 -> gnupg.org/ftp/gcrypt/… ,你们自己看着下。
生成公钥
安装好了之后,在你的命令行里面执行
gpg --full-gen-key
- 模式选择
RAS and RAS
- 长度选
4096
- 有效期选
0
,无限期,确认 - 名字、邮箱、说明看着填
- 最后输入
O
确定
gpg: checking the trustdb
.../gnupg/pubring.kbx
-----------------------------------------------
pub rsa4096 2021-02-03 [SC]
7A5D73CFEDDDBC915986998A36271B955BEF072A
uid [ultimate] Marton Braun (Example key for tutorial) <marton@getstream.io>
sub rsa4096 2021-02-03 [E]
你会得到这样的结果,请牢记那一长串字符就是你的公钥,后面一般填的就是它的后八位5BEF072A
,还要牢记的就是你输入的name
后面也要的。
生成私钥
gpg --export-secret-keys -o secring.gpg
输入一个password
生成一个私钥文件,找到它并牢记
你的密码,后面会用到。
上传公钥
公钥需要上传到公共仓库,一边后面做验证,公钥仓库有很多 Sonatype 的比对地址应该是改过,我按照网上的教程到pgp.mit.edu
后面死活验证不过。这里我们传两个地方,以防万一。
gpg --keyserver hkp://pool.sks-keyservers.net --send-keys 5BEF072A
gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 5BEF072A
好了,第二部也完成了。准备好你的私钥文件和密码,我们开始下一步。
脚本
要想找到一个新的,确认能用的脚本有多难你们知道吗?这里含泪推荐publish-mavencentral.gradle,先把它下下来放到我们项目的根目录。然后我们来配置~
修改
这个脚本虽然可以用但是我们还是得修改修改。
-
首先这个脚本打包
javadocJar
的时候支持Kotlin
,我的项目没有,删掉。 -
然后这个项目是我们公司提供出去的
SDK
,并不公开源码,所以源码打包的部分也屏蔽掉。 -
然后就是一些描述、开源协议、项目地址、开发者看着天上自己的就行。
-
再就是他这个脚本还支持什么自动上传,太麻烦还容易出错,删掉。
这些都是可选的,你们有这个需求,还有看得懂groovy
语法的可以改一下,要不然还是就这原样。
最重
原来的releasesRepoUrl
和snapshotsRepoUrl
在2021年2月之后就改了,新的都是在https://s01.oss.sonatype.org/
上配置,如果你之前的项目传过,那还是在https://oss.sonatype.org/
。这个我之前一直没注意到,太坑了。
这个是我的脚本文件,应该看懂不难,参考一下自己改成自己的
apply plugin: 'maven-publish'
apply plugin: 'signing'
task androidSourcesJar(type: Jar) {
archiveClassifier.set('sources')
from 'src/main/java/develop'
from 'src/main/java/develop'
}
task javadocs(type: Javadoc) {
source = 'src/main/java/null'
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
excludes = ['**/*.kt']
}
task javadocJar(type: Jar, dependsOn: javadocs) {
archiveClassifier.set('javadoc')
from javadocs.destinationDir
}
artifacts {
archives androidSourcesJar
archives javadocJar
}
group = PUBLISH_GROUP_ID
version = PUBLISH_VERSION
ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.secretKeyRingFile"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(secretPropsFile))
p.each { name, value ->
ext[name] = value
}
} else {
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
ext["signing.secretKeyRingFile"] = System.getenv('SIGNING_SECRET_KEY_RING_FILE')
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
}
publishing {
publications {
release(MavenPublication) {
// The coordinates of the library, being set from variables that
// we'll set up later
groupId PUBLISH_GROUP_ID
artifactId PUBLISH_ARTIFACT_ID
version PUBLISH_VERSION
if (project.plugins.findPlugin("com.android.library")) {
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
} else {
artifact("$buildDir/libs/${project.getName()}-${version}.jar")
}
// Two artifacts, the `aar` (or `jar`) and the sources
artifact androidSourcesJar
artifact javadocJar
// Mostly self-explanatory metadata
pom {
name = PUBLISH_ARTIFACT_ID
description = 'DouTingLtd Android SDK'
url = 'https://github.com/DouTingLtd/AndroidSample'
licenses {
license {
name = 'The Apache Software License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'XiaoSeee'
name = 'XiaoSe'
email = 'wuxiang@tinglibao.com.cn'
}
}
// Version control info - if you're using GitHub, follow the format as seen here
scm {
connection = 'scm:https://github.com/DouTingLtd/AndroidSample.git'
developerConnection = 'scm:https://github.com/DouTingLtd/AndroidSample.git'
url = 'https://github.com/DouTingLtd/AndroidSample'
}
// A slightly hacky fix so that your POM will include any transitive dependencies
// that your library builds upon
withXml {
def dependenciesNode = asNode().appendNode('dependencies')
project.configurations.implementation.allDependencies.each {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}
}
}
}
// The repository to publish to, Sonatype/MavenCentral
repositories {
maven {
// This is an arbitrary name, you may also use "mavenCentral" or
// any other name that's descriptive for you
name = "mavenCentral"
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username ossrhUsername
password ossrhPassword
}
}
}
}
signing {
sign publishing.publications
}
local.properties
然后找到你项目的local.properties
文件,里面天上:
signing.keyId=5BEF072A
signing.password=signingPass123
signing.secretKeyRingFile=~/gpg-keys/5BEF072A.gpg
ossrhUsername=yourSonatypeUser
ossrhPassword=yourSonatypePassword
Library Module
最后在你Module
的build.gradle
里加上:
ext {
PUBLISH_GROUP_ID = 'com.github.doutingltd'
PUBLISH_VERSION = '0.8.7'
PUBLISH_ARTIFACT_ID = 'core'
}
apply from: '../publish-mavencentral.gradle'
额外提一点,你的 Library 如果没有使用架包就把这句话删掉把,他实测它会再你的 pom 文件里添加一个叫unspecified
的依赖,导致使用你库的人找不到这个依赖从而编译失败。
// implementation fileTree(dir: 'libs', include: ['*.jar'])
<dependency>
<groupId/>
<artifactId>unspecified</artifactId>
<version/>
</dependency>
提交
Sync 一下你的项目,你可以看到你的 Module 下面会有一个 publishReleasePublicationToXXXXXXRepository
的 Tasks,XXXX
是你脚本里面填的 name = "mavenCentral"
,说明你可以提交了。运行:
./gradlew clean :mod_sdk:build
./gradlew :mod_sdk:publishReleasePublicationToMavenCentralRepository
审核
登录 s01.oss.sonatype.org/ (老项目可能是:oss.sonatype.org/)
选中文件,点击Close
就开始验证了,点击Activity
标签,可以看到你正在验证的过程,过一会如果没问题你可以看到下面通过的界面:
最后点击Release
按钮进行发布,有一个确认对话框,您可以选择“自动删除”,以便在发行完成后清理登台存储库。
回复 Issue
新建的项目还需要去最开始提的 Issue 进行回复,告诉他们你版本发布成功了,他们会给你开通 Maven Central 的权限。后面再更新就不用了。
完结
ok,十几分钟后你的库就可以再 -> s01.oss.sonatype.org/content/rep… 这里面找到了,这时候别人就能引用下载了。等待个个把小时,你的库还能在这里被搜索到了 -> search.maven.org/
可以去项目里测试一下:
implementation 'com.github.doutingltd:core:0.8.7'
记得再根build.gradle
中添加maven
库快照地址:
...
allprojects {
repositories {
...
mavenCentral()
}
}
...
jcenter
要跑路了建议大家先删掉 jcenter() 试试你的项目还能编译码?