发布开源库到Maven Central

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

注册Sonatype账号

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

创建问题

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

验证Group Id

等待工作人员回复,会要求在域名解析添加一个TXT记录,并包含问题编号,验证所有权完成,就可以上传项目了

发布项目

在要发布的Library创建publish.gradle,粘贴模板,此模板支持Android、Java、Gradle插件

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
apply plugin: 'maven-publish'
apply plugin: 'signing'

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

def mavenUsername = localProperties.getProperty("sonatype.username")
def mavenPassword = localProperties.getProperty("sonatype.password")
def projectGroupId = project.ext.groupId
def projectArtifactId = project.getName()
def projectVersionName = project.ext.has('version') ? project.ext.getProperty('version') : project.extensions.findByName("android")["defaultConfig"].versionName
def projectDescription = project.ext.has('description') ? project.ext.getProperty('description') : null
def projectGitUrl = project.ext.has('gitUrl') ? project.ext.getProperty('gitUrl') : null
def projectLicense = project.ext.has('license') ? project.ext.getProperty('license') : null
def projectLicenseUrl = projectLicense ? "https://opensource.org/licenses/${projectLicense.toString().replace(" ", "-")} " : null

def developerAuthorId = mavenUsername
def developerAuthorName = mavenUsername
def developerAuthorEmail = project.ext.has('authorEmail') ? project.ext.getProperty('authorEmail') : null

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

if (!mavenUsername || !mavenPassword || !projectGroupId || !projectArtifactId || !projectVersionName) {
println('错误:缺少参数')
return
}
if (!projectDescription || !projectGitUrl || !projectLicense || !projectLicenseUrl || !developerAuthorId || !developerAuthorName || !developerAuthorEmail) {
println('警告:缺少可选信息')
}

def isAndroidProject = project.hasProperty('android')
if (isAndroidProject) {
println("使用Android工程方式发布")
// Android 工程
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task javadocsJar(type: Jar, dependsOn: androidJavadocs) {
archiveClassifier.set("javadoc")
from androidJavadocs.destinationDir
}
task sourcesJar(type: Jar) {
archiveClassifier.set("sources")
from android.sourceSets.main.java.srcDirs
}
} else {
println("使用Java工程方式发布")
// Java 工程
task javadocsJar(type: Jar, dependsOn: javadoc) {
archiveClassifier.set("javadoc")
from javadoc.destinationDir
}
task sourcesJar(type: Jar) {
archiveClassifier.set("sources")
from sourceSets.main.allJava
}
}

tasks.withType(Javadoc).all {
options {
encoding "UTF-8"
charSet 'UTF-8'
author true
version true
links "http://docs.oracle.com/javase/8/docs/api"
if (isAndroidProject) {
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
}
failOnError = false
}
enabled = false
}

artifacts {
archives javadocsJar, sourcesJar
}

publishing {
publications {
aar(MavenPublication) {
groupId = projectGroupId
artifactId = projectArtifactId
version = projectVersionName
// Tell maven to prepare the generated "*.aar" file for publishing
if (isAndroidProject){
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
}else{
artifact("$buildDir/libs/${project.getName()}.jar")
}
artifact javadocsJar
artifact sourcesJar

pom {
name = projectArtifactId
description = projectDescription
// If your project has a dedicated site, use its URL here
url = projectGitUrl
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 {
def dependenciesNode = asNode().appendNode('dependencies')
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
2
3
4
5
6
7
8
ext {
groupId = 'in.xiandan'
description = '全局耗时计算器,可以在任何地方计算耗时' //项目
gitUrl = 'https://github.com/xiandanin/AnyCost' //Git地址,不包含.git
authorEmail = 'example@example.com' // 作者邮箱
license = 'MIT' //开源协议,可选
}
apply from: 'publish.gradle'

创建密钥

创建证书

生成密钥对

创建个人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
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