SDK发布到maven Central,实现远程依赖

3,867 阅读9分钟

最近大学同学约了一顿饭,主题是”结束北漂“,这哥们是我们的生活委员,平时非常热心,也非常nice,我就给他起了一个外号,名叫”主席“,最近主席突然说要离开北京了,请在北京的同学吃饭,我们一行几个人相聚到了北京”东兴楼“。

主席说”来北京5年了,当时来北京的时候就定下了这个目标,在北京奋斗5年,现在5年零一个月,要结束北漂生活,回老家了,如果考研顺利,就上研究生,如果不顺利就继续在上海当程序员,至少离家近一点。“

确实很快,一转眼都5年了,我们扯了扯大学的日常,工作的烦心事,以及对主席日后的祝福,就这样简单一顿饭,给主席壮了行。

最近很忙,一直也没来的级更文,年后组织结构变化,我也换了领导,一切都从新开始,从头出发...

我们最近在做一个三方SDK,其实在Android开发中,SDK开发基本属于日常,只是SDK的用途和集成方式有差异。

我之前最早主要要系统级SDK,简单来说就是把SDK集成到手机系统模块里。

这种情况一般都是将SDK打包直接邮件给手机厂商,比如华/米/O/V,然后手机厂商根据附件的SDK进行本地依赖。

最近公司要做一个三方SDK,业务方是市场上各个应用媒体,接入环境复杂,接入方众多。

一般三方SDK开发都会尽量保证以下几个原则

    1. 低耦合,尽量少引用或者不引用其他三方包。
    1. 体积,尽量小,能动态化的尽量动态化(当然你的动态化需要跟三方说明,不能随便上功能)
    1. 稳定性,无论出现什么问题,一定不能崩溃,你的崩溃会影响主站App的崩溃。
    1. 性能,内存占用/功耗尽可能小,这个其实是和业务量强相关的。
    1. 便捷性,SDK接口的设计,尽可能简介,易用,减少不必要的参数,和方法。
    1. 兼容性,这一点需要注意,如果SDK迭代的频率很高,这一点是保证接入友好的先决条件。

开始我们通过FAT-AAR将集团所有的内部库直接打进了SDK,放到了开发平台。

每个三方App通过平台注册,申请appkey,然后下载SDK进行本地依赖。

但是后来对接过程中发现,三方app有的已经接入了集团的其他SDK,比如支付宝SDK,阿里云SDK,这些SDK中也用到了相同的二方库,这时就会产生类冲突,又因为是FAT-AAR合并打包,所以没办法exclude,这时答疑变成了一个非常消耗精力的过程。

在这个背景下,解决这个问题的思路主要有以下几点。

    1. 拆分打包,把SDK分开产出,让需求方逐个下载并依赖(如有冲突就选择性依赖)
    1. 把集团包源码拉取到自己项目,统一把前缀包名修改,从根源解决类冲突。
    1. 将我们的SDK放到maven中心仓库,通过implementation进行远程依赖,连带依赖打进pom.xml,三方一键式引用,一键式exclude。

经过再三斟酌,以及接入体验。最终决定采用第3个方案,第3个方案需要上传到maven中心仓库,这个过程之前没有接触过,参考了各个大佬的博客,都没能一站式解决问题,还是有各种坑,最终一路趟坑总结了这篇maven中心仓库的发布过程。

maven中心仓库发布分为以下几大步骤。

    1. Sonatype注册账号,创建项目提工单,做域名配置。
    1. gpg安装,配置,秘钥生成,秘钥上传。
    1. 完成本地上传脚本,开始上传。

Sonatype注册

首先需要去Sonatype注册一个账号,就像这样

image.png

image.png

注册完成后开始创建项目 image.png

image.png

创建完项目,相关的工作人员会让你做一个添加DNS TXT的工作。 image.png

意思是你需要有一个groupid的域名,然后让你在域名下添加一条记录,记录内容为你当前创建的项目单编号。

比如:添加[OSSRH-78888],主要是为了证明你是这个groupid的所有者,防止恶意注册。

具体添加DNS TXT的方法可以参考下这个链接

central.sonatype.org/faq/how-to-…

DNS TXT可以在创建完项目单就去添加,因为maven仓的工作人员跟我们有时差,他们一般是晚上,半夜回复你的项目单,这样你第二天看到跟他再交流,他又得等到半夜再回复你,比较耗时间。

创建成功后大概是这样一个页面

image.png

安装gpg

mac环境 好多人会让你通过brew命令去安装,比如brew install gpg,但是我是安装不上的,因为我的mac系统是12.3,比较新,gpg不支持了,会报如下错误

image.png 我们可以去这里下载gnupg.org/ftp/gcrypt/…

如果不想选这些版本可以无脑点这个链接下载:gnupg.org/ftp/gcrypt/…,这个直接是下载2.3.4的版本

image.png

windows 可以去这里下载:www.gpg4win.org/get-gpg4win…

下完后,安装,然后需要配置下环境变量

export GPG_HOME=/usr/local/gnupg-2.3/bin

export PATH=${PATH}:${GPG_HOME}

安装并配置好gpg后,主要需要以下几个步骤

  • 1.产生秘钥key
  • 2.输入passphrase
  • 3.查看秘钥
  • 4.上传秘钥
  • 5.查看秘钥是否长传成功
  • 6.删除秘钥(这个主要是因为我开始摸索生成一堆没有用的秘钥)
  • 7.到处秘钥

1.生成秘钥

gpg --gen-key

image.png

2.输入name email这些基础信任,然后输入o会弹窗让设置密码,这个密码非常重要,目前我还不知道密码忘记怎么办,所以到这一步的时候,一定记一下这个秘钥

圈起来的都是输入信息 image.png image.png

3.查看秘钥

gpg --list-keys(主要用于查看当前秘钥是不是生成成功了)

image.png

4.上传秘钥

gpg --keyserver hkp://keyserver.ubuntu.com:11371 —send-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25 这一步主要是把当前的秘钥发布到服务器,使得maven中心仓能验证到你的身份。

这里好多人都失败。

第一是这个服务不是很稳定。

第二是你的翻墙不太稳定。

可以往三个服务器里上传,只要成功一个就可以。

gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25
gpg --keyserver hkp://keys.openpgp.org:11371 --send-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25
gpg --keyserver hkp://pool.sks-keyservers.net:11371 --send-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25

5.查看秘钥是否上传成功 gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25

如果一直返回No keyserver available就是没有成功。 由于上传服务器不同,所以查询也需要多个服务器查询

gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25
gpg --keyserver hkp://keys.openpgp.org:11371 --recv-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25
gpg --keyserver hkp://pool.sks-keyservers.net:11371 --recv-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25

6.删除秘钥

删除秘钥需要2步骤,第1需要先删除私钥,第2步再删除公钥。

gpg --delete-secret-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25

image.png

gpg --delete-keys 4624BE8EC49928575D81F9D5C68ED8702A95ED25

image.png

中途需要输入创建秘钥时候的密码。 image.png

7.导出私钥 gpg --export-secret-keys -o my.gpg 这个可以放在自己的主工程根目录。

3.编写打包上传脚本

3.1 在根目录gradle.properties添加配置
#这是我们sdk的groupId,主要用于三方远程依赖使用。
groupId=你的groupId
#是否仅发布到Snapshots,如果为false则发布正式版本
publish2Snapshots=false
#MavenCentral发布
releaseUrl=https://s01.oss.sonatype.org/content/repositories/releases/
snapshotsUrl=https://s01.oss.sonatype.org/content/repositories/snapshots/

#这个不要动,这是工程的pgp私钥配置和私钥密码、sign keyId & password
signing.keyId= 你的私钥id(就是你私钥的后8位)
signing.password=你私钥的密码(就是不让你忘记的那一个)
#sign my.gpg可放在工程根目录,私钥文件,不要动!!!
signing.secretKeyRingFile=../my.gpg

#account,这个是maven仓库的用户名和密码
ossrhUsername=你第一步maven仓库的账号
ossrhPassword=你第一步maven仓库的密码

##这个没什么大用,主要用于pom.xml文件的个别标签描述code url
sdkUrl= 这里填你的官网就行
sdkGitUrl= 如果你们sdk是开源的,可以填开源的git地址,没开源就填你们官网
3.2 完成编译上传脚本upload.gradle,放到主工程根目录。

//本脚本主要用于上传包到maven仓库
//1.依赖主工程的gradle.properties配置
//2.依赖java类的常量来写入当前的sdk版本;
apply plugin: 'maven-publish'
apply plugin: 'signing'

group = groupId
//读取java类的常量版本号字符串
def buildConfigFile = file('../Testc/main/java/com/test/C.java')

buildConfigFile.eachLine {
    def matcher = (it =~ /(?:.*SdkVersion = ")(.*)(?:".*)/)
    if (matcher.matches()) {
        if (Boolean.valueOf(publish2Snapshots)) {
            version = matcher[0][1] + "-SNAPSHOT"
        } else {
            version = matcher[0][1]
        }
        println("当前版本号为.......>>>>>>" + "$version")
        return
    }
}


//以下这些包需要添加到pom.xml文件中
def implementationJar = ["glide", "fastjson", "okhttp", "okio"] as String[]

publishing {
    publications {
        mavenCentralUpload(MavenPublication) {
            artifact "$libTargetFile"
            artifactId = "$libName"
            pom {
                name = libName
                description = libDescription
                url = sdkUrl
                licenses {
                    license {
                        name = "The Apache License, Version 2.0"
                        url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
                    }
                }
                developers {
                    developer {
                        id = "这里写你的项目id"
                        name = "SDK名称"
                        email = "项目邮箱"
                    }
                }
                scm {
                    connection = sdkGitUrl
                    developerConnection = sdkGitUrl
                    url = sdkUrl
                }

                withXml {
                    def dependenciesNode = asNode().appendNode("dependencies")
                    configurations.implementation.allDependencies.forEach() { dependency ->
                         if (implementationJar.contains(dependency.name)) {
                                //只将我们定义到implementationJar数组的包打进pom
                                println("now build pom dependency.name :" + dependency.name)
                                if (dependency.version != "unspecified" && dependency.name != "unspecified") {
                                    def dependencyNode = dependenciesNode.appendNode('dependency')
                                    dependencyNode.appendNode('groupId', dependency.group)
                                    dependencyNode.appendNode('artifactId', dependency.name)
                                    dependencyNode.appendNode('version', dependency.version)
                                }
                            }

                    }
                }
            }

        }
    }

    repositories {
        maven {
            def targetUrl
            if (Boolean.valueOf(publish2Snapshots)) {
                targetUrl = snapshotsUrl
            } else {
                targetUrl = releaseUrl
            }
            url = targetUrl
            credentials {
                username = ossrhUsername
                password = ossrhPassword
            }
        }
    }
}

signing {
    sign publishing.publications.mavenCentralUpload
}

3.3 最后在需要打包的module/build.gradle中增加以下配置
apply from: '../upload.gradle'
project.afterEvaluate {
    publish.dependsOn assembleRelease
}
3.4执行编译上传命令
./gradlew :你的moudle:publish

上传sdk后,可以去中心仓库搜索查看 s01.oss.sonatype.org/#welcome

这里需要注意新老仓库的地址

image.png 官网有说明,这里说2021年2月以后的全都是新地址s01.oss.sonatype.org/

之前的可以在老地址使用oss.sonatype.org/.

image.png 但是项目依赖需要等待一会才能远程依赖到,因为仓库是海外的地址下载比较慢,为了效率可以在工程的build.gradle中增加以下镜像

maven { url 'https://maven.aliyun.com/repository/public' }

阿里这个镜像会定时同步maven中心仓库。

以上就是上传maven中心仓库的全过程,如果对你有所帮助麻烦帮点个赞吧亲.....