发布组件到 Maven 私服、公服

5,251 阅读3分钟

前言

  • 欢迎任何形式的转载,转载请保留原文链接:juejin.cn/post/709167…
  • 文章主要内容:讲述如何发布组件到 Maven 私服、Maven Central

目录

  • 发布组件到 Maven 私服
  • 发布组件到 Maven Central

发布组件到 Maven 私服

创建 maven_private.gradle,内容如下

// maven 插件
apply plugin: 'maven'

// 打包的资源内容,关于 javaDoc 部分,至今未找到能用的
task androidSourcesJar(type: Jar) {
    classifier = 'sources'
    from android.sourceSets.main.java.srcDirs
}

artifacts {
    archives androidSourcesJar
}

// maven 打包并上传,发布到 maven-releases
uploadArchives {
    repositories.mavenDeployer {
        // Nexus 服务器地址与登录信息
        repository(url: "${maven_domain}/repository/maven-releases/") {
            authentication(userName: maven_release_user, password: maven_release_password)
        }

        // pom.xml 标签含义参考:http://www.javashuo.com/article/p-zlitehoa-eg.html
        pom.project {
            groupId ''
            artifactId ''
            version ''
            description ''
        }

        doLast {
            println "【${project.name}】项目,【${repository.authentication.userName}】用户," +
                    "成功往【${repository.url}】发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"
        }
    }
}

// maven 打包并上传,发布到 maven-dev
task uploadDevArchives(group: 'upload') {
    def firstTask = rootProject.startTasks[0]
    if (firstTask != null && firstTask.endsWith('uploadDevArchives')) {
        uploadArchives {
            repositories.mavenDeployer {
                repository(url: "${maven_domain}/repository/maven-dev/") {
                    authentication(userName: maven_user, password: maven_password)
                }
            }
        }
        uploadDevArchives.dependsOn uploadArchives
    }
}

项目 gradle.properties,添加以下内容

maven_domain            = http://127.0.0.1:8081
maven_release_user      = admin
maven_release_password  = admin
maven_user              = admin
maven_password          = admin

项目目录/build.gradle,添加以下内容

android {
    defaultConfig {
        versionCode 1
        versionName "1.0.0"
    }
}

// maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称
apply from: "${rootDir.path}/gradle/maven_private.gradle"
uploadArchives {
    repositories.mavenDeployer {
        pom.project {
            groupId 'io.github.jefshi'
            artifactId 'lib-log'
            version android.defaultConfig.versionName
            description '日志打印工具'
        }
    }
}

同步项目后,Gradle Tasks 就会生成 uploadArchive 任务,执行 uploadArchives,出现以下结果表示上传成功

Task :xxx:uploadArchives
【xxx】项目,【xxx】用户,成功往【http://127.0.0.1:8081/repository/maven-releases/】发布版本:io.github.jefshi:lib-log:1.0.0

BUILD SUCCESSFUL in 1s
23 actionable tasks: 2 executed, 21 up-to-date
21:21:57: Task execution finished 'uploadArchives'.

上述添加了一个自定义任务 uploadDevArchives,可以直接上传到 maven-dev 仓库,其他 maven-xxx 仓库以此类推

组件发布成功后,通过 implementation 'io.github.jefshi:lib-log:1.0.0@aar' 下载使用

发布组件到 Maven Central

简要步骤(详细说明见下)

官方发布指南,简化如下:central.sonatype.org/publish/pub…

  1. 注册 Sonatype 的账户。地址:issues.sonatype.org/secure/Sign…
  2. 提交发布申请。创建 Issue 地址:issues.sonatype.org/secure/Crea…
  3. 生成 GPG 密钥对,并发布到 GPG 密钥服务器
  4. Gradle 方式上传组件到 OSS 仓库
  5. 登录 OSS maven 服务器 release 组件
  6. 通知 Sonatype 的工作人员激活组件,并关闭 Issue
    • 回复参考:Thanks, I release my repository successful. Could you activate my sync process?

  7. 使用组件,见第 4 步上传组件章节说明。如果要检索的话,则得等 1-2 天

其他说明:

  • Sonatype 工作人员是北京时间 22:00 之后上班的,所以在这之前就不用等了,再这之后倒响应挺快的

提交发布申请

  1. 创建 Issue 地址:issues.sonatype.org/secure/Crea…
  2. Project:Community Support - Open Source Project Repository Hosting
  3. Issue Type:New Project
  4. 点击下一步后,具体的填写可以参考:issues.sonatype.org/browse/OSSR…
    • Summary:lib-log
    • Group Id:io.github.jefshi,这个必须是可访问域名倒写
    • Already Synced to Central:No

生成 GPG 密钥对,并发布到 GPG 密钥服务器

因为 Maven Central 要求文件进行 GPG/PGP 签名,所以要生成 GPG 密钥对

  1. Sonatype 官网要求说明:central.sonatype.org/publish/req…
  2. Sonatype 官网 GPG 指南:central.sonatype.org/publish/req…
  3. Window 使用 Cygwin 安装 gnupg 即可取得 gpg 命令

上述官网中需要用到的命令汇总

# 检查安装成功没
gpg --version

# 生成密钥对
gpg --gen-key

# 查看公钥
gpg --list-keys

# 将公钥发布到 GPG 密钥服务器
gpg --keyserver keyserver.ubuntu.com --send-keys 公钥ID

# 查询公钥是否发布成功
gpg --keyserver keyserver.ubuntu.com --recv-keys 公钥ID

# 将公钥从 GPG 密钥服务器上移除
gpg --keyserver keyserver.ubuntu.com --delete-secret-keys 公钥ID
gpg --keyserver keyserver.ubuntu.com --delete-keys 公钥ID

生成密钥对:gpg --gen-key

  1. 密钥匹配:一路回车取默认值,最后确认即可
  2. 要求输入姓名、邮箱,然后确认
  3. 还需要输入一个 Passphase,相当于一个密钥库的密码,一定不要忘了,也不要告诉别人,最好记下来,因为后面会用到

查看公钥:gpg --list-keys

  • 下述命令输出信息里【82DC852E】就是公钥ID。【hy_think hy_think@163.com】则是 USER-ID
$ gpg --list-keys
C:/Users/huangyong/AppData/Roaming/gnupg/pubring.gpg
----------------------------------------------------
pub   2048R/82DC852E 2014-04-24
uid                  hy_think <hy_think@163.com>
sub   2048R/3ACA39AF 2014-04-24

GPG 密钥服务器还可以用以下

  • keyserver.ubuntu.com
  • keys.openpgp.org
  • pgp.mit.edu

Gradle 方式上传组件到 OSS 仓库(aar版)

  1. Sonatype 官网说明:central.sonatype.org/publish/pub…
  2. OSS 仓库地址(来源于上述官网):s01.oss.sonatype.org
  3. OSS 仓库账户密码:即 Sonatype 的账户密码

因为官方插件关于 GPG 密钥信息要么写在项目的gradle.properties,要么写在~/.gradle/gradle.properties(Gradle 缓存),明显后者安全性高,如果后者不存在的话手动新建即可

# GPG 配置信息
signing.keyId = 公钥ID
signing.password = GPG 密码
signing.secretKeyRingFile = ~/.gnupg/secring.gpg

# OSS 仓库账户密码
ossrhUsername = OSS 账户,这个倒可以写在 local.properties
ossrhPassword = OSS 密码,同上

创建 maven_central.gradle,内容如下

// maven 插件
apply plugin: 'maven'
apply plugin: 'signing'

// 打包的资源内容,关于 javaDoc 部分,至今未找到能用的
task androidSourcesJar(type: Jar) {
    archiveClassifier.set("sources")
    from android.sourceSets.main.java.srcDirs
}

artifacts {
    archives androidSourcesJar
}

// GPG 密钥签名,配置信息放【~/.gradle/gradle.properties】
signing {
    sign configurations.archives
}

// maven 打包并上传
uploadArchives {
    repositories.mavenDeployer {
        beforeDeployment {
            MavenDeployment deployment -> signing.signPom(deployment)
        }

        repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
            authentication(userName: ossrhUsername, password: ossrhPassword)
        }

        snapshotRepository(url: "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
            authentication(userName: ossrhUsername, password: ossrhPassword)
        }

        // pom.xml 标签含义参考:http://www.javashuo.com/article/p-zlitehoa-eg.html
        pom.project {
            name POM_NAME
            groupId POM_GROUP_ID
            artifactId POM_ARTIFACT_ID
            version POM_VERSION_NAME
            packaging POM_PACKAGING

            description POM_DESCRIPTION
            url POM_URL

            // 配置代码库,为 Maven 站点和其它插件使用
            scm {
                url POM_SCM_URL
                developerConnection POM_SCM_DEV_CONNECTION
                connection POM_SCM_CONNECTION
            }

            // 证书
            licenses {
                license {
                    name POM_LICENCE_NAME
                    url POM_LICENCE_URL
                    distribution POM_LICENCE_DISTRIBUTION
                }
            }

            // 开发者信息
            developers {
                developer {
                    id POM_DEVELOPER_ID
                    name POM_DEVELOPER_NAME
                    email POM_DEVELOPER_EMAIL
                }
            }
        }

        doLast {
            println "【${project.name}】项目,【${repository.authentication.userName}】用户," +
                    "成功往【${repository.url}】发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"
        }
    }
}

项目 gradle.properties,添加以下内容

  • 关于 pom.xml 标签含义参考:www.javashuo.com/article/p-z…
  • 关于 groupId:必须以 Issue 中申请的 group_id 开头,后面可以加其他内容,同时 Gradle 会按该值创建缓存目录
  • 建议:本文为了保证完整性,这里的变量是全量说明的,实际封装与使用完全可以简化
# maven_central 相关
POM_NAME                 = lib-log
POM_GROUP_ID             = io.github.jefshi,必须以 Issue 中申请的 group_id 开头,Gradle 会按该值创建缓存目录
POM_ARTIFACT_ID          = lib-log
POM_PACKAGING            = aar
POM_VERSION_NAME         = 1.0.0
POM_DESCRIPTION          = 日志打印工具
POM_URL                  = https://github.com/jefshi/lib-log
POM_SCM_URL              = https://github.com/jefshi/lib-log
POM_SCM_CONNECTION       = scm:git@github.com:jefshi/lib-log.git
POM_SCM_DEV_CONNECTION   = scm:git@github.com:jefshi/lib-log.git
POM_LICENCE_NAME         = The Apache License, Version 2.0
POM_LICENCE_URL          = http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DISTRIBUTION = repo
POM_DEVELOPER_ID         = jefshi
POM_DEVELOPER_NAME       = jefshi
POM_DEVELOPER_EMAIL      = -

待发布 module 目录/build.gradle,添加以下内容

apply from: "${rootDir.path}/gradle/maven_central.gradle"

如果一个项目下有多个 aar 需要发布或者自定义部分属性,则可以在【待发布 module 目录/build.gradle】里添加如下内容(参考范例仅自定义 version 属性,其余属性自行根据需要添加)

uploadArchives {
    repositories.mavenDeployer {
        pom.project {
            version android.defaultConfig.versionName
        }
    }
}

同步下项目,Gradle Tasks 就会生成 uploadArchive 任务,执行 uploadArchives,出现以下结果表示上传组件成功

Task :xxx:uploadArchives
【xxx】项目,【xxx】用户,成功往【https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/】发布版本:io.github.jefshi:lib-log:1.0.0

BUILD SUCCESSFUL in 1s
23 actionable tasks: 2 executed, 21 up-to-date
21:21:57: Task execution finished 'uploadArchives'.

上述配置组件发布并激活成功后,通过implementation 'io.github.jefshi:lib-log:1.0.0'下载使用

Gradle 方式上传组件到 OSS 仓库(jar版)

除了 maven_central.gradle 内容需要做调整外,其余和 aar 发布一样,调整后内容如下:

  • 建议创建 maven_central_jar.gradle,这样 jar 和 aar 版的可以共存
// maven 插件
apply plugin: 'maven'
apply plugin: 'signing'

// 打包的资源内容,关于 javaDoc 部分,至今未找到能用的
task javadocJar(type: Jar) {
    archiveClassifier.set("javadoc")
    from javadoc
}

task sourcesJar(type: Jar) {
    archiveClassifier.set("sources")
    from sourceSets.main.allSource
}

artifacts {
    // archives javadocJar
    archives sourcesJar
}

// GPG 密钥签名,配置信息放【~/.gradle/gradle.properties】
signing {
    sign configurations.archives
}

// maven 打包并上传
uploadArchives {
    repositories.mavenDeployer {
        beforeDeployment {
            MavenDeployment deployment -> signing.signPom(deployment)
        }

        repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
            authentication(userName: ossrhUsername, password: ossrhPassword)
        }

        snapshotRepository(url: "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
            authentication(userName: ossrhUsername, password: ossrhPassword)
        }

        // pom.xml 标签含义参考:http://www.javashuo.com/article/p-zlitehoa-eg.html
        pom.project {
            name POM_NAME
            groupId POM_GROUP_ID
            artifactId POM_ARTIFACT_ID
            version POM_VERSION_NAME
            packaging POM_PACKAGING

            description POM_DESCRIPTION
            url POM_URL

            // 配置代码库,为 Maven 站点和其它插件使用
            scm {
                url POM_SCM_URL
                developerConnection POM_SCM_DEV_CONNECTION
                connection POM_SCM_CONNECTION
            }

            // 证书
            licenses {
                license {
                    name POM_LICENCE_NAME
                    url POM_LICENCE_URL
                    distribution POM_LICENCE_DISTRIBUTION
                }
            }

            // 开发者信息
            developers {
                developer {
                    id POM_DEVELOPER_ID
                    name POM_DEVELOPER_NAME
                    email POM_DEVELOPER_EMAIL
                }
            }
        }

        doLast {
            println "【${project.name}】项目,【${repository.authentication.userName}】用户," +
                    "成功往【${repository.url}】发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"
        }
    }
}

记得把项目 gradle.properties 的以下内容调整下,或者直接写到 maven_central_jar.gradle 中,建议后者

POM_PACKAGING = jar

登录 OSS maven 服务器发布组件

  1. Sonatype 官网指南:central.sonatype.org/publish/rel…
  2. OSS 仓库地址(来源于上述官网):s01.oss.sonatype.org
  3. OSS 仓库账户密码:即 Sonatype 的账户密码

发布说明

  • 登录 OSS 仓库,在左边菜单找到【Staging Repositories】,选中上传的组件
  • 可以发现这时你的构件状态是“open”,勾选你的构件,查看校验的结果信息,如果没有错误就可以点击刚才勾选的checkbox上面右边一点的“close”按钮,在弹出框中“confirm”,这里又需要校验一次,稍后结果会通过邮箱通知。

  • 等成功后(系统自动进行,很快的),再次登录系统找到你的构件,这是状态已经是“closed”的了,再次勾选,然后点击“close”旁边的“release”,在弹出框中进行“confirm”,稍后结果会通过邮件进行通知。

参考文献

版本同步

博客同步版本:

  • 2022-06/23:补充 Gradle 方式上传 jar 库
  • 2022-04-28:首发博客