发布组件到 Maven 私服、公服

5,620 阅读4分钟

发布组件到 Maven 私服、公服

前言

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

目录

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

发布组件到 Maven 私服

创建 maven_publish.gradle,内容如下
- 包含一个使用 demo 说明,具体步骤见代码后文字详细说明

/**  
 * 发布组件到 Maven 私服  
 * @version 1.0.0  
 */  
  
// 使用 Demo(2步)  
// 1. 待发布 module 目录/build.gradle 添加以下内容,可增删减  
// // maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称  
//apply from: "${rootDir.path}/gradle/maven_publish.gradle"  
// afterEvaluate {  
//     publishing {  
//         publications {  
//             mavenLib(MavenPublication) {  
//                 groupId = POM_GROUP_ID  
//                 artifactId = '组件ID,可带-'  
//                 version = '1.0.0-SNAPSHOT' // 要么没有[SNAPSHOT],要么[SNAPSHOT]必须大写  
//                 version = android.defaultConfig.versionName // [SNAPSHOT] 必须大写  
//                 pom {  
//                     description = '描述'  
//                 }  
//             }  
//         }  
//     }  
// }  
// 2. gradle.properties 文件配置添加以下内容  
// # maven_publish.gradle 相关  
// maven_domain               =http://127.0.0.1:8081  
// maven_release_user         =私服账户相关  
// maven_release_password     =  
// maven_user                 =  
// maven_password             =  
// aliyun_maven_release       =阿里云私服账户相关  
// aliyun_maven_snapshot      =  
// aliyun_maven_username      =  
// aliyun_maven_password      =  
  
// maven 插件  
apply plugin: 'maven-publish'  
  
def isJar = project.plugins.hasPlugin('java')  
def isAar = project.plugins.hasPlugin('com.android.library')  
  
/**  
 * 按以下顺序加载属性(直至有值):  
 * 1. local.properties 文件  
 * 2. gradle.properties 文件(用于 setting.gradle 阶段无 project 的场景)  
 * 3. Gradle 缓存仓库下的 gradle.properties 文件  
 * 4. Java 虚拟机的系统属性  
 * 5. 操作系统的环境变量  
 */  
def loadProperties = { String filePath ->  
    File file = file(filePath)  
    if (file == null  
            || file.isDirectory()  
            || !file.exists()) {  
        return null  
    }  
  
    Properties properties = new Properties()  
    properties.load(file.newDataInputStream())  
    return properties  
}  
def localProperties = loadProperties("${rootDir.path}/local.properties")  
def gradleProperties = loadProperties("${rootDir.path}/gradle.properties")  
def repoProperties = loadProperties(gradle.gradleUserHomeDir.path + "/gradle.properties")  
def loadProperty = { String propertyName ->  
    try {  
        def value = null  
        if (localProperties != null) {  
            value = localProperties[propertyName]  
        }  
        if (gradleProperties != null && (value == null || value == "")) {  
            // setting 阶段无 project,所以无法使用 value = project.property(propertyName)  
            value = gradleProperties[propertyName]  
        }  
        if (repoProperties != null && (value == null || value == "")) {  
            value = repoProperties[propertyName]  
        }  
        if (value == null || value == "") {  
            value = System.getProperty(propertyName)  
        }  
        if (value == null || value == "") {  
            value = System.getenv(propertyName)  
        }  
        return value  
    } catch (Exception e) {  
        throw new Exception("==================== 相关必要配置参数缺失,请补全 ====================", e)  
    }  
}  
  
// maven 打包并上传  
// 官方文档:https://docs.gradle.org/current/userguide/publishing_maven.html  
afterEvaluate {  
    // afterEvaluate 主要目的是获取已配置好的其他配置信息,如 bundleReleaseAar 任务、android.defaultConfig.versionName  
    publishing {  
        repositories {  
            // 一个远程仓库配置,生成并对应一个 publish发布名称PublicationTo仓库名称Repository 任务  
            def maven_domain = loadProperty("maven_domain")  
            maven {  
                // 私服 maven-releases 仓库  
                name 'releases'  
                url = "${maven_domain}/repository/maven-releases"  
                credentials {  
                    username = loadProperty("maven_release_user")  
                    password = loadProperty("maven_release_password")  
                }  
            }  
            maven {  
                // 私服 maven-snapshots 仓库  
                name 'snapshots'  
                url = "${maven_domain}/repository/maven-snapshots"  
                credentials {  
                    username = loadProperty("maven_user")  
                    password = loadProperty("maven_password")  
                }  
            }  
            maven {  
                // 阿里云 release 仓库  
                name 'aLiYunRelease'  
                url = "https://packages.aliyun.com/maven/repository/" + loadProperty("aliyun_maven_release")  
                credentials {  
                    username = loadProperty("aliyun_maven_username")  
                    password = loadProperty("aliyun_maven_password")  
                }  
            }  
            maven {  
                // 阿里云 snapshot 仓库  
                name 'aLiYunSnapshots'  
                url = "https://packages.aliyun.com/maven/repository/" + loadProperty("aliyun_maven_snapshot")  
                credentials {  
                    username = loadProperty("aliyun_maven_username")  
                    password = loadProperty("aliyun_maven_password")  
                }  
            }  
        }  
  
        publications {  
            // 一个发布配置,生成并对应一个 publish发布名称PublicationTo仓库名称Repository 任务  
            mavenLib(MavenPublication) {  
                if (isJar) {  
                    from components.java  
                    // artifact javadocJar  
                    artifact sourcesJar  
                } else if (isAar) {  
                    artifact androidSourcesJar  
                    artifact bundleReleaseAar  
                }  
  
                groupId = POM_GROUP_ID  
                artifactId = POM_ARTIFACT_ID  
                version = '0.0.0-SNAPSHOT' // [SNAPSHOT] 必须大写  
  
                // pom.xml 标签含义参考:http://www.javashuo.com/article/p-zlitehoa-eg.html  
                pom {  
                    description = POM_DESCRIPTION  
                }  
            }  
        }  
    }  
}  
  
// 任务:打包的资源内容  
if (isJar) {  
    // 注意 javaDoc 目前无法使用,这部分官方文档(下述)有变更  
    [javadoc]*.options*.encoding = 'UTF-8'  
    task javadocJar(type: Jar, group: 'publishing') {  
        archiveClassifier.set("javadoc")  
        from javadoc  
    }  
    task sourcesJar(type: Jar, group: 'publishing') {  
        archiveClassifier.set("sources")  
        from sourceSets.main.allSource  
    }  
}  
if (isAar) {  
    // 关于 javaDoc 部分,至今未找到能用的  
    task androidSourcesJar(type: Jar) {  
        archiveClassifier.set("sources")  
        from android.sourceSets.main.java.srcDirs  
    }  
}  
// 发布成功后,打印发布信息  
tasks.withType(PublishToMavenRepository) {  
    doLast {  
        // mavenLib 源于前面的 publishing 里的发布配置名称  
        def pom = publishing.publications.mavenLib  
        def repo = it.name.endsWith('ToSnapshotsRepository') ? publishing.repositories.snapshots  
                : it.name.endsWith('ToReleasesRepository') ? publishing.repositories.releases  
                : it.name.endsWith('ToALiYunSnapshotsRepository') ? publishing.repositories.aLiYunSnapshots  
                : it.name.endsWith('ToALiYunReleaseRepository') ? publishing.repositories.aLiYunRelease  
                : null  
        if (repo == null) {  
            println "【${project.name}】项目,成功往未知远程 Maven 仓库发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"  
        } else {  
            println "【${project.name}】项目,【${repo.credentials.username}】用户," +  
                    "成功往【${repo.url}】发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"  
        }  
    }  
}  
tasks.withType(PublishToMavenLocal) {  
    doLast {  
        // mavenLib 源于前面的 publishing 里的发布配置名称  
        def pom = publishing.publications.mavenLib  
        println "【${project.name}】项目,成功往本地 Maven 缓存发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"  
    }  
}  

使用第一步:待发布 module 目录/build.gradle,添加以下内容
- 意思是如果一个项目下有多个 aar 需要发布,则各自的 build.gradle 都需要添加

// maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称  
apply from: "${rootDir.path}/gradle/maven_publish_central.gradle"  
afterEvaluate {  
    publishing {  
        publications {  
            mavenLib(MavenPublication) {  
                groupId = POM_GROUP_ID  
                artifactId = '组件ID,可带-'  
                version = '1.0.0-SNAPSHOT' // 要么没有[SNAPSHOT],要么[SNAPSHOT]必须大写  
                version = android.defaultConfig.versionName // [SNAPSHOT] 必须大写  
                pom {  
                    description = '描述'  
                }  
            }  
        }  
    }  
}  

实际案例:

// maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称  
apply from: "${rootDir.path}/gradle/maven_publish.gradle"  
afterEvaluate {  
    publishing {  
        publications {  
            mavenLib(MavenPublication) {  
                version = android.defaultConfig.versionName // [SNAPSHOT] 必须大写  
            }  
        }  
    }  
}  

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

# maven_publish.gradle 相关  
maven_domain            =http://127.0.0.1:8081  
maven_release_user      =私服账户相关  
maven_release_password  =  
maven_user              =  
maven_password          =  
aliyun_maven_release    =阿里云私服账户相关  
aliyun_maven_snapshot   =  
aliyun_maven_username   =  
aliyun_maven_password   =  

按上文 Gradle 脚本会生成任务,publishMavenLibPublicationToReleasesRepository,执行出现以下结果表示上传组件成功
- 任务名称规则:publish + 配置名称 + PublicationTo + 仓库名称 + Repository,故多配置、多仓库会组合生成若干任务看

> Task :lib-log-android:publishMavenLibPublicationToReleasesRepository  
【lib-log】项目,【xxxx】用户,成功往【http://127.0.0.1:8081/repository/maven-releases/】发布版本:io.github.jefshi:lib-log:1.0.0  
  
BUILD SUCCESSFUL in 18s  
26 actionable tasks: 2 executed, 24 up-to-date  
22:04:05: Execution finished 'publishMavenLibPublicationToReleasesRepository'.  

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

发布组件到 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?
- Sonatype 工作人员是北京时间 22:00 之后上班的,所以在这之前就不用等了,再这之后倒响应挺快的 
7. 使用组件,见第 4 步上传组件章节说明。如果要检索的话,则得等 1-2 天
- > 中央仓库搜索网站:search.maven.org/

提交发布申请

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 命令,2024年已要求版本 2.2.19 以上

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

# 检查安装成功没  
gpg --version  
  
# 生成密钥对  
gpg --gen-key  
  
# 查看公钥  
gpg --list-keys  
gpg --list-keys --keyid-format short  
  
# 将公钥发布到 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 --export-secret-keys > ~/.gnupg/secring.gpg  

生成密钥对:gpg --gen-key
1. 要求输入姓名、邮箱,然后确认
2. > 还需要输入一个 Passphase,相当于一个密钥库的密码,一定不要忘了,也不要告诉别人,最好记下来,因为后面会用到

查看公钥:gpg --list-keys
- 下述命令输出信息里【CA925CD6C9E8D064FF05B4728190C4130ABA0F98】就是公钥ID。【Central Repo Test central@example.com】则是 USER-ID

$ gpg --list-keys  
[keyboxd]  
---------  
pub   rsa3072 2021-06-23 [SC] [expires: 2023-06-23]  
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98  
uid           [ultimate] Central Repo Test <central@example.com>  
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]  

GPG 密钥服务器还可以用以下
- keyserver.ubuntu.com
- keys.openpgp.org
- pgp.mit.edu

Gradle 方式上传组件到 OSS 仓库(aar版与jar版都可用)

创建 maven_central.gradle,内容如下
- 包含一个使用 demo 说明,具体步骤见代码后文字详细说明

/**  
 * 发布组件到 Maven Central  
 * @version 1.0.0  
 */  
  
// 使用 Demo(3步)  
// 1. 待发布 module 目录/build.gradle 添加以下内容,可增删减  
// // maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称  
// apply from: "${rootDir.path}/gradle/maven_publish_central.gradle"  
// afterEvaluate {  
//     publishing {  
//         publications {  
//             mavenLib(MavenPublication) {  
//                 groupId = POM_GROUP_ID  
//                 artifactId = '组件ID,可带-'  
//                 version = '1.0.0-SNAPSHOT' // 要么没有[SNAPSHOT],要么[SNAPSHOT]必须大写  
//                 version = android.defaultConfig.versionName // [SNAPSHOT] 必须大写  
//                 pom {  
//                     description = '描述'  
//                 }  
//             }  
//         }  
//     }  
// }  
// 2. gradle.properties 文件配置添加以下内容  
// # maven_publish_central.gradle 相关  
// POM_GROUP_ID           = 以 Sonatype 账户 Issue 中申请的 group_id 开头  
// POM_ARTIFACT_ID        = 组件ID  
// POM_DESCRIPTION        = 组件描述  
// POM_SCM_URL            = 项目访问地址,如 github 地址  
// POM_SCM_CONNECTION     = 项目源码下载地址,如 github clone 地址  
// POM_DEVELOPER_ID       = 开发者ID  
// POM_DEVELOPER_NAME     = 开发者名称  
// POM_DEVELOPER_EMAIL    = 开发者邮箱  
// 3. ~/.gradle/gradle.properties 文件配置添加以下内容  
// # GPG 配置信息  
// signing.keyId = 公钥ID(的最后8位)  
// signing.password = GPG 密码  
// signing.secretKeyRingFile = ~/.gnupg/secring.gpg  
//  
// # OSS 仓库账户密码  
// ossrhUsername = OSS 账户,这个倒可以写在 local.properties  
// ossrhPassword = OSS 密码,同上  
  
// maven 插件  
apply plugin: 'maven-publish'  
apply plugin: 'signing'  
  
def isJar = project.plugins.hasPlugin('java')  
def isAar = project.plugins.hasPlugin('com.android.library')  
  
// maven 打包并上传  
// 官方文档:https://docs.gradle.org/current/userguide/publishing_maven.html  
// Maven Central 官方要求文档:https://central.sonatype.org/publish/requirements/  
afterEvaluate {  
    // afterEvaluate 主要目的是获取已配置好的其他配置信息,如 bundleReleaseAar 任务、android.defaultConfig.versionName  
    publishing {  
        repositories {  
            // Maven Central 账户密码:为安全考虑,只会从全局的 gradle.properties 读取  
            def ossrhUsername = null  
            def ossrhPassword = null  
            try {  
                ossrhUsername = project.property("ossrhUsername")  
                ossrhPassword = project.property("ossrhPassword")  
            } catch (Exception ignored) {  
            }  
  
            // 一个远程仓库配置,生成并对应一个 publish发布名称PublicationTo仓库名称Repository 任务  
            maven {  
                name 'releases'  
                url = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'  
                credentials {  
                    username = ossrhUsername  
                    password = ossrhPassword  
                }  
            }  
            maven {  
                name 'snapshots'  
                url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'  
                credentials {  
                    username = ossrhUsername  
                    password = ossrhPassword  
                }  
            }  
        }  
  
        publications {  
            // 一个发布配置,生成并对应一个 publish发布名称PublicationTo仓库名称Repository 任务  
            mavenLib(MavenPublication) {  
                if (isJar) {  
                    from components.java  
                    // artifact javadocJar  
                    artifact sourcesJar  
                } else if (isAar) {  
                    artifact androidSourcesJar  
                    artifact bundleReleaseAar  
                }  
  
                groupId = POM_GROUP_ID  
                artifactId = POM_ARTIFACT_ID  
                version = '0.0.0-SNAPSHOT' // [SNAPSHOT] 必须大写  
  
                // pom.xml 标签含义参考:http://www.javashuo.com/article/p-zlitehoa-eg.html  
                pom {  
                    name = artifactId  
                    description = POM_DESCRIPTION  
                    url = POM_SCM_URL  
  
                    // 配置代码库,为 Maven 站点和其它插件使用  
                    scm {  
                        url = POM_SCM_URL  
                        developerConnection = POM_SCM_CONNECTION  
                        connection = POM_SCM_CONNECTION  
                    }  
  
                    // 证书  
                    licenses {  
                        license {  
                            name = 'The Apache License, Version 2.0'  
                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'  
                            distribution = 'repo'  
                        }  
                    }  
  
                    // 开发者信息  
                    developers {  
                        developer {  
                            id = POM_DEVELOPER_ID  
                            name = POM_DEVELOPER_NAME  
                            email = POM_DEVELOPER_EMAIL  
                        }  
                    }  
                }  
            }  
        }  
    }  
    // GPG 密钥签名,配置信息放【~/.gradle/gradle.properties】  
    signing {  
        // 会根据前面的 publishing 里的发布配置名称,生成一个以 sign 开头的任务,本配置为:signMavenLibPublication  
        // 签名成功会在 build/outputs 下有 asc 格式文件  
        required true  
        sign publishing.publications  
    }  
}  
  
// 任务:打包的资源内容  
if (isJar) {  
    // 注意 javaDoc 目前无法使用,这部分官方文档(下述)有变更  
    [javadoc]*.options*.encoding = 'UTF-8'  
    task javadocJar(type: Jar, group: 'publishing') {  
        archiveClassifier.set("javadoc")  
        from javadoc  
    }  
    task sourcesJar(type: Jar, group: 'publishing') {  
        archiveClassifier.set("sources")  
        from sourceSets.main.allSource  
    }  
}  
if (isAar) {  
    // 关于 javaDoc 部分,至今未找到能用的  
    task androidSourcesJar(type: Jar) {  
        archiveClassifier.set("sources")  
        from android.sourceSets.main.java.srcDirs  
    }  
}  
  
// 发布成功后,打印发布信息  
tasks.withType(PublishToMavenRepository) {  
    doLast {  
        // mavenLib 源于前面的 publishing 里的发布配置名称  
        def pom = publishing.publications.mavenLib  
        def repo = it.name.endsWith('ToSnapshotsRepository') ? publishing.repositories.snapshots  
                : it.name.endsWith('ToReleasesRepository') ? publishing.repositories.releases  
                : null  
        if (repo == null) {  
            println "【${project.name}】项目,成功往未知远程 Maven 仓库发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"  
        } else {  
            println "【${project.name}】项目,【${repo.credentials.username}】用户," +  
                    "成功往【${repo.url}】发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"  
        }  
    }  
}  
tasks.withType(PublishToMavenLocal) {  
    doLast {  
        // mavenLib 源于前面的 publishing 里的发布配置名称  
        def pom = publishing.publications.mavenLib  
        println "【${project.name}】项目,成功往本地 Maven 缓存发布版本:${pom.groupId}:${pom.artifactId}:${pom.version}"  
    }  
}  

使用第一步:待发布 module 目录/build.gradle,添加以下内容
- 意思是如果一个项目下有多个 aar 需要发布,则各自的 build.gradle 都需要添加

// maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称  
apply from: "${rootDir.path}/gradle/maven_publish_central.gradle"  
afterEvaluate {  
    publishing {  
        publications {  
            mavenLib(MavenPublication) {  
                groupId = POM_GROUP_ID  
                artifactId = '组件ID,可带-'  
                version = '1.0.0-SNAPSHOT' // 要么没有[SNAPSHOT],要么[SNAPSHOT]必须大写  
                version = android.defaultConfig.versionName // [SNAPSHOT] 必须大写  
                pom {  
                    description = '描述'  
                }  
            }  
        }  
    }  
}  

实际案例:

// maven 发布,必须在 android.defaultConfig.versionName 配置之后,以便获取版本名称  
apply from: "${rootDir.path}/gradle/maven_publish_central.gradle"  
afterEvaluate {  
    publishing {  
        publications {  
            mavenLib(MavenPublication) {  
                version = android.defaultConfig.versionName // [SNAPSHOT] 必须大写  
            }  
        }  
    }  
}  

使用第二步:项目 gradle.properties,添加以下内容
- 关于 pom.xml 标签含义参考:www.javashuo.com/article/p-z…
- 关于 groupId:必须以 Sonatype 账户 Issue 中申请的 group_id 开头,后面可以加其他内容,同时 Gradle 会按该值创建缓存目录
- 建议:本文为了保证完整性,这里的变量是全量说明的,实际封装与使用完全可以简化

# maven_publish_central.gradle 相关  
POM_GROUP_ID           = 以 Sonatype 账户 Issue 中申请的 group_id 开头  
POM_ARTIFACT_ID        = 组件ID  
POM_DESCRIPTION        = 组件描述  
POM_SCM_URL            = 项目访问地址,如 github 地址  
POM_SCM_CONNECTION     = 项目源码下载地址,如 github clone 地址  
POM_DEVELOPER_ID       = 开发者ID  
POM_DEVELOPER_NAME     = 开发者名称  
POM_DEVELOPER_EMAIL    = 开发者邮箱  

实际案例

# maven_central 相关  
POM_GROUP_ID           = io.github.jefshi  
POM_ARTIFACT_ID        = lib-log  
POM_DESCRIPTION        = 轻量级日志打印工具  
POM_SCM_URL            = https://github.com/jefshi/lib-log  
POM_SCM_CONNECTION     = scm:git@github.com:jefshi/lib-log.git  
POM_DEVELOPER_ID       = jefshi  
POM_DEVELOPER_NAME     = jefshi  
POM_DEVELOPER_EMAIL    = -  

使用第三步:GPG 签名配置与 OSS 账户配置:
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.secretKeyRingFile 的文件路径通过导出私钥证书 gpg --export-secret-keys > ~/.gnupg/secring.gpg 生成
- 验证 GPG 配置信息:
- 配置成功:按上文 Gradle 脚本,执行 signMavenLibPublication 成功
- 签名成功:按上文 Gradle 脚本,执行 publishMavenLibPublicationToMavenLocal 成功后 build/outputs 下有 asc 格式文件
- OSS 仓库账户密码:OSS 的访问 token(获取步骤:登录后—点击账户—Profile—Access User Token)

<server>  
  <id>${server}</id>  
  <username>xxxx</username>  
  <password>xxxx</password>  
</server>  
# GPG 配置信息  
signing.keyId = 公钥ID(的最后8位)  
signing.password = GPG 密码  
signing.secretKeyRingFile = ~/.gnupg/secring.gpg  
  
# OSS 仓库账户密码  
ossrhUsername = OSS User Token 的 <username>  
ossrhPassword = OSS User Token 的 <password>  

按上文 Gradle 脚本会生成任务,publishMavenLibPublicationToReleasesRepository,执行出现以下结果表示上传组件成功
- 任务名称规则:publish + 配置名称 + PublicationTo + 仓库名称 + Repository,故多配置、多仓库会组合生成若干任务

> Task :lib-log-android:publishMavenLibPublicationToReleasesRepository  
【lib-log】项目,【xxxx】用户,成功往【https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/】发布版本:io.github.jefshi:lib-log:1.0.0  
  
BUILD SUCCESSFUL in 18s  
26 actionable tasks: 2 executed, 24 up-to-date  
22:04:05: Execution finished 'publishMavenLibPublicationToReleasesRepository'.  

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

登录 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”,稍后结果会通过邮件进行通知。

参考文献

- 将项目发布到 Maven 中央仓库踩过的坑:brianway.github.io/2017/05/17/…
- 将 Smart 构件发布到 Maven 中央仓库:my.oschina.net/huangyong/b…
- 发布Maven构件到中央仓库:my.oschina.net/songxinqian…
- 使用Gradle发布开源项目到Maven Central:developer.51cto.com/article/464…
- Gradle Maven Publish 官方文档:docs.gradle.org/current/use…
- Maven Central 官方要求文档:central.sonatype.org/publish/req…
- pom.xml 标签含义参考:www.javashuo.com/article/p-z…

版本同步

博客同步版本:
- 2024-11-06:Gradle 7.0 以上更换 maven-publish 插件、按 maven central 最新要求修改、整合 aar、jar 上传脚本(自动识别)
- 2022-06/23:补充 Gradle 方式上传 jar 库
- 2022-04-28:首发博客