Android Gradle 脚本发布开源库至 mavenCentral

1,358 阅读7分钟

背景

以前我们 Android 开发引用的第三方库都是通过jcenter()库依赖来的,很多库也是发布在上面的,包括我们公司的的。但是最近jcenter已经跑路了!这个是新闻链接,大致意思是说2021年3月31号之后就不能提交新的库了,旧的库2022年2月1号还可以提供下载,之后旧不能了。所以项目中用jcenter()依赖的库,之后就很有可能就编译不成功了,不巧的是据大部分项目都是依赖的jcenter(),因为是Google默认的。

计划

既然jcenter()跑路了,那我们就换一个,mavenCentral()就是我们今天要讲的。这个仓库也是一直存在的,目前一些比较大的库例如:retrofitglide等等都已经转移到这个上面了。但是这个仓库上传的准备工作及其麻烦,真的是费了我九牛二虎之力去研究,网上很多资料都过时了,填了好多坑终于搞定了,现在把步骤写下来做个备份,也给其他人一个参考。

注册

Sonatype 账户

mavenCentral 仓库是属于 Sonatype 管理的,我们需要注册一个他们家的账号 -> 网址

注册完了,登录后回让你选择一个工作:

0_q4VkOApO78ZlcZBh.png

这里我们选择Create an issue

0_Yviy7Mt-mF5dLbpN.png

然后我们选择Community Support — Open Source Project Repository HostingNew Project

Group Id:

解释

再填下面东西之前,我们先看上面的图了解下什么是GROUP_IDARTIFACT_IDVERSION,其中GROUP_ID比较重要,我们等下要填的。Sonatype 管理比较严,这是他们的要求,英文好的仔细看看。如果你的GROUP_ID填的格式着这种公司的名字像:com.tencent.mm.opensdk他后面审核的时候会要求你证明tencent.com这个域名是属于你的。

对于一般个人开发者可能你并没有相应的域名,又或者你们公司域名不归你管理,这种认证就比较麻烦。我就属于这种,所以我们退而求其次,只能把GROUP_ID填成github的这种形式,像这样com.github.xxxx。这个xxx还必须是你的GitHubusername

GlideGROUP_ID就是com.github.bumptech.glide。当然你按照他们的要求来会审核会比较块,实在有特殊情况你就得和他们得审核人员掰扯掰扯了,也不是不可以。我英语不好懒得掰扯,就把我之前用的GROUP_ID给换掉了,反正也没人用🤣~

后面的ARTIFACT_IDVERSION是可随意。

Create

0_6AusjndZxCF30XVl.png

其他的就比较好理解了,照着要求填就是了

  • Summary: 说明下你要来干嘛
  • Description: 说明下你要来干嘛
  • Group Id: 你的 group ID,
  • Project URL: 项目的URL
  • SCM url: 代码的URL,一般写git的链接

认证

填完了一会之后会看到下面有人评论你的Issue应该是要求你去GitHub建立一个他要求的repo,按照他的要求建完了之后,回复他,然后他再验证。等你们掰扯完了之后他就会告诉你,你的GROUP_ID准备好了,你可以去提交项目了,那么恭喜了第一步完成了。

密钥

在提交你的包的时候他们还要求有个加密验证,没搞懂是干嘛的,反正照着做就完了...

安装GnuPG

官网下载一个你操作系统的你的安装包,我是Windows 10,下载的是这个 -> gnupg.org/ftp/gcrypt/… ,你们自己看着下。

生成公钥

安装好了之后,在你的命令行里面执行

gpg --full-gen-key
  • 模式选择RAS and RAS
  • 长度选4096
  • 有效期选0,无限期,确认
  • 名字、邮箱、说明看着填
  • 最后输入O确定
gpg: checking the trustdb
.../gnupg/pubring.kbx
-----------------------------------------------
pub   rsa4096 2021-02-03 [SC]
      7A5D73CFEDDDBC915986998A36271B955BEF072A
uid           [ultimate] Marton Braun (Example key for tutorial) <marton@getstream.io>
sub   rsa4096 2021-02-03 [E]

你会得到这样的结果,请牢记那一长串字符就是你的公钥,后面一般填的就是它的后八位5BEF072A,还要牢记的就是你输入的name后面也要的。

生成私钥

gpg --export-secret-keys -o secring.gpg

输入一个password生成一个私钥文件,找到它并牢记你的密码,后面会用到。

上传公钥

公钥需要上传到公共仓库,一边后面做验证,公钥仓库有很多 Sonatype 的比对地址应该是改过,我按照网上的教程到pgp.mit.edu后面死活验证不过。这里我们传两个地方,以防万一。

gpg --keyserver hkp://pool.sks-keyservers.net --send-keys 5BEF072A
gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 5BEF072A

好了,第二部也完成了。准备好你的私钥文件和密码,我们开始下一步。

脚本

要想找到一个新的,确认能用的脚本有多难你们知道吗?这里含泪推荐publish-mavencentral.gradle,先把它下下来放到我们项目的根目录。然后我们来配置~

修改

这个脚本虽然可以用但是我们还是得修改修改。

  • 首先这个脚本打包javadocJar的时候支持Kotlin,我的项目没有,删掉。

  • 然后这个项目是我们公司提供出去的SDK,并不公开源码,所以源码打包的部分也屏蔽掉。

  • 然后就是一些描述、开源协议、项目地址、开发者看着天上自己的就行。

  • 再就是他这个脚本还支持什么自动上传,太麻烦还容易出错,删掉。

这些都是可选的,你们有这个需求,还有看得懂groovy语法的可以改一下,要不然还是就这原样。

最重

原来的releasesRepoUrlsnapshotsRepoUrl在2021年2月之后就改了,新的都是在https://s01.oss.sonatype.org/上配置,如果你之前的项目传过,那还是在https://oss.sonatype.org/。这个我之前一直没注意到,太坑了。

这个是我的脚本文件,应该看懂不难,参考一下自己改成自己的

apply plugin: 'maven-publish'
apply plugin: 'signing'

task androidSourcesJar(type: Jar) {
    archiveClassifier.set('sources')
    from 'src/main/java/develop'
    from 'src/main/java/develop'
}

task javadocs(type: Javadoc) {
    source = 'src/main/java/null'
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    excludes = ['**/*.kt']
}

task javadocJar(type: Jar, dependsOn: javadocs) {
    archiveClassifier.set('javadoc')
    from javadocs.destinationDir
}

artifacts {
    archives androidSourcesJar
    archives javadocJar
}

group = PUBLISH_GROUP_ID
version = PUBLISH_VERSION

ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.secretKeyRingFile"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''

File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
    Properties p = new Properties()
    p.load(new FileInputStream(secretPropsFile))
    p.each { name, value ->
        ext[name] = value
    }
} else {
    ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
    ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
    ext["signing.secretKeyRingFile"] = System.getenv('SIGNING_SECRET_KEY_RING_FILE')
    ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
    ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
}

publishing {
    publications {
        release(MavenPublication) {
            // The coordinates of the library, being set from variables that
            // we'll set up later
            groupId PUBLISH_GROUP_ID
            artifactId PUBLISH_ARTIFACT_ID
            version PUBLISH_VERSION
            if (project.plugins.findPlugin("com.android.library")) {
                artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
            } else {
                artifact("$buildDir/libs/${project.getName()}-${version}.jar")
            }

            // Two artifacts, the `aar` (or `jar`) and the sources
            artifact androidSourcesJar
            artifact javadocJar

            // Mostly self-explanatory metadata
            pom {
                name = PUBLISH_ARTIFACT_ID
                description = 'DouTingLtd Android SDK'
                url = 'https://github.com/DouTingLtd/AndroidSample'
                licenses {
                    license {
                        name = 'The Apache Software License, Version 2.0'
                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }
                developers {
                    developer {
                        id = 'XiaoSeee'
                        name = 'XiaoSe'
                        email = 'wuxiang@tinglibao.com.cn'
                    }
                }
                // Version control info - if you're using GitHub, follow the format as seen here
                scm {
                    connection = 'scm:https://github.com/DouTingLtd/AndroidSample.git'
                    developerConnection = 'scm:https://github.com/DouTingLtd/AndroidSample.git'
                    url = 'https://github.com/DouTingLtd/AndroidSample'
                }
                // A slightly hacky fix so that your POM will include any transitive dependencies
                // that your library builds upon
                withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')

                    project.configurations.implementation.allDependencies.each {
                        def dependencyNode = dependenciesNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', it.group)
                        dependencyNode.appendNode('artifactId', it.name)
                        dependencyNode.appendNode('version', it.version)
                    }
                }
            }
        }
    }
    // The repository to publish to, Sonatype/MavenCentral
    repositories {
        maven {
            // This is an arbitrary name, you may also use "mavenCentral" or
            // any other name that's descriptive for you
            name = "mavenCentral"

            def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl

            credentials {
                username ossrhUsername
                password ossrhPassword
            }
        }
    }
}

signing {
    sign publishing.publications
}

local.properties

然后找到你项目的local.properties文件,里面天上:

signing.keyId=5BEF072A
signing.password=signingPass123
signing.secretKeyRingFile=~/gpg-keys/5BEF072A.gpg 
ossrhUsername=yourSonatypeUser
ossrhPassword=yourSonatypePassword

Library Module

最后在你Modulebuild.gradle里加上:

ext {
    PUBLISH_GROUP_ID = 'com.github.doutingltd'
    PUBLISH_VERSION = '0.8.7'
    PUBLISH_ARTIFACT_ID = 'core'
}
apply from: '../publish-mavencentral.gradle'

额外提一点,你的 Library 如果没有使用架包就把这句话删掉把,他实测它会再你的 pom 文件里添加一个叫unspecified的依赖,导致使用你库的人找不到这个依赖从而编译失败。

// implementation fileTree(dir: 'libs', include: ['*.jar'])
<dependency>
	<groupId/>
	<artifactId>unspecified</artifactId>
	<version/>
</dependency>

提交

Sync 一下你的项目,你可以看到你的 Module 下面会有一个 publishReleasePublicationToXXXXXXRepository 的 Tasks,XXXX 是你脚本里面填的 name = "mavenCentral",说明你可以提交了。运行:

./gradlew clean :mod_sdk:build
./gradlew :mod_sdk:publishReleasePublicationToMavenCentralRepository

审核

登录 s01.oss.sonatype.org/ (老项目可能是:oss.sonatype.org/)

选中文件,点击Close就开始验证了,点击Activity标签,可以看到你正在验证的过程,过一会如果没问题你可以看到下面通过的界面:

0_-Yvt1XDdUfOBtfC5.png

最后点击Release按钮进行发布,有一个确认对话框,您可以选择“自动删除”,以便在发行完成后清理登台存储库。

回复 Issue

新建的项目还需要去最开始提的 Issue 进行回复,告诉他们你版本发布成功了,他们会给你开通 Maven Central 的权限。后面再更新就不用了。

完结

ok,十几分钟后你的库就可以再 -> s01.oss.sonatype.org/content/rep… 这里面找到了,这时候别人就能引用下载了。等待个个把小时,你的库还能在这里被搜索到了 -> search.maven.org/

可以去项目里测试一下:

implementation 'com.github.doutingltd:core:0.8.7'

记得再根build.gradle中添加maven库快照地址:

...
allprojects {
    repositories {
        ...
        mavenCentral()
    }
}
...

jcenter 要跑路了建议大家先删掉 jcenter() 试试你的项目还能编译码?