发布开源库到Maven Central

JCenter宣布停用后,今后只能发布到Maven Central,相对JCenter,首次发布到Maven Central要麻烦很多

注册Sonatype账号

https://issues.sonatype.org/secure/ForgotLoginDetails.jspa

创建问题

填写项目信息,Group Id可以填自己的域名,或者com.github.自己的用户名,后面会验证所有权

验证Group Id

几分钟后会有一个机器人回复,要求验证域名的所有权

  • 用域名作为Group Id:域名解析一个TXT记录,内容就是当前问题编号
  • 用Github用户名作为Group Id:创建一个名称为当前问题编号的仓库

将问题标记为打开

等待几分钟会回复验证成功,就可以上传项目了

发布项目

在要工程根目录创建publish.gradle,粘贴模板,此模板支持Android、Java、Kotlin、Gradle Plugin
publish.gradle代码地址:https://gist.github.com/xiandanin/6a215a24acee9e8194bc4668b3e8f133

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
apply plugin: 'maven-publish'
apply plugin: 'signing'

Properties localProperties = new Properties()
// 合并local.properties
localProperties.load(project.rootProject.file('local.properties').newDataInputStream())
localProperties.each { name, value -> project.ext[name] = value }

Map<String, String> projectProperties = new HashMap<>()
// 合并project.ext
projectProperties.putAll(project.ext.getProperties())
// 合并rootProject.ext
rootProject.ext.getProperties().each { name, value -> if (!projectProperties.containsKey(name)) projectProperties.put(name, value) }
//println(properties)
def mavenUsername = localProperties.getProperty("sonatype.username")
def mavenPassword = localProperties.getProperty("sonatype.password")
def projectGroupId = projectProperties.get('groupId')
def projectArtifactId = project.getName()
def projectVersionName = projectProperties.getOrDefault('version', project.extensions.findByName("android")["defaultConfig"].versionName)
def projectDescription = projectProperties.get('description')
def projectGitUrl = projectProperties.get('gitUrl')
def projectLicense = projectProperties.get('license')
def projectLicenseUrl = projectLicense ? "https://opensource.org/licenses/${projectLicense.toString().replace(" ", "-")} " : null

def developerAuthorId = mavenUsername
def developerAuthorName = mavenUsername
def developerAuthorEmail = projectProperties.get('authorEmail')

println("${mavenUsername} ${mavenPassword} - ${projectGroupId}:${projectArtifactId}:${projectVersionName}")
println("${projectLicense} - ${projectLicenseUrl}")

if (!projectGroupId || !projectArtifactId || !projectVersionName) {
println("${project.name} 缺少项目信息")
return
}
if (!mavenUsername || !mavenPassword || !localProperties.containsKey("signing.keyId") || !localProperties.containsKey("signing.password") || !localProperties.containsKey("signing.secretKeyRingFile")) {
println("${project.name} 缺少认证信息")
return
}
if (!projectDescription || !projectGitUrl || !projectLicense || !projectLicenseUrl || !developerAuthorId || !developerAuthorName || !developerAuthorEmail) {
println("${project.name} 缺少项目描述信息")
}

android {
publishing {
singleVariant("release") {
withSourcesJar()
withJavadocJar()
}
}
}

afterEvaluate {
publishing {
publications {
aar(MavenPublication) {
from components.release

groupId = projectGroupId
artifactId = projectArtifactId
version = projectVersionName

pom {
name = projectArtifactId
description = projectDescription
// If your project has a dedicated site, use its URL here
url = projectGitUrl
if (projectLicense) {
licenses {
license {
name = projectLicense
url = projectLicenseUrl
}
}
}
developers {
developer {
id = developerAuthorId
name = developerAuthorName
email = developerAuthorEmail
}
}
// Version control info, if you're using GitHub, follow the format as seen here
scm {
connection = "scm:git:${projectGitUrl}"
developerConnection = "scm:git:${projectGitUrl}"
url = projectGitUrl
}
withXml { xmlProvider ->
def node = xmlProvider.asNode()
def getAt = node.getAt('dependencies')
def dependenciesNode
if (getAt == null) {
dependenciesNode = node.appendNode('dependencies')
} else {
dependenciesNode = getAt[0]
}
configurations.api.allDependencies.each { dependency ->
if (!dependency.hasProperty('dependencyProject')) {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
}
}
}
}
}
}

repositories {
maven {
name = projectArtifactId

def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
// You only need this if you want to publish snapshots, otherwise just set the URL
// to the release repo directly
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl

// The username and password we've fetched earlier
credentials {
username mavenUsername
password mavenPassword
}
}
}
}
}

signing {
sign publishing.publications
}

在要发布的Library工程下的build.gradle最后引用发布模板

1
apply from: '../publish.gradle'

在工程根目录的build.gradle最后添加项目信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ext {
// 版本号
versionCode = 3
// 版本名称
versionName = "1.0.2"
// groupId
groupId = 'io.xiandan'
// 项目描述
description = 'JSONObject、JSONArray、Gson的Koltin扩展'
// 项目git地址
gitUrl = 'https://github.com/xiandanin/json-ktx'
// 作者邮箱
authorEmail = 'denghahae@gmail.com'
// 开源协议
license = 'MIT'
}

创建密钥

创建证书

生成密钥对

创建个人OpenPGP密钥对

勾选Protect the generated key with a passphrase.,输入密码

复制指纹后8位作为signing.keyId

生成撤销证书

右键证书,在服务器上发布,最后会发布在http://keys.gnupg.net

右键Backup Secret Keys...导出私钥证书,后缀名改为gpg

填写认证信息

将Sonatype账号和密钥信息填写到local.propertiessigning.secretKeyRingFile就是最后导出的.gpg路径

1
2
3
4
5
6
sonatype.username=
sonatype.password=

signing.keyId=
signing.password=
signing.secretKeyRingFile=

发布

执行publish任务,或者命令行执行gradlew publish

任务执行完成后,登录https://s01.oss.sonatype.org/#stagingRepositories,选中刚刚上传的提交,点击Close

无报错提示Repository Closed说明执行完成,点击Release,等待几十分钟就会同步到Maven Central

首次发布同步

因为这个Group Id是首次发布,发布项目后,要手动通知同步到Maven Central,将Already Synced to Central标记为Yes,等待几个小时就可以在Maven Central看到项目了