Android Studio发布jar到Sonatype Maven Central

最近在整理一个项目,希望能分享给人类。折腾老半天,终于献出去了:


com.github.2ndlines:download:+

谨此此篇记录我踩过的坑,以及如何爬出坑。希望对读者有所帮助。

电脑环境:
OS: Mac OS 10.14.4
IDE:Android Studio 3.5
GPG:2.2.8

步骤一:源码准备

在Android Studio中完成项目开发和测试,尽可能的保证您贡献的项目好用耐用;

步骤二:向Sonatype提交工单

坑位预警:Group Id要求唯一
工单提交地址:https://issues.sonatype.org/secure/Dashboard.jspa
这是一个JIRA平台,如果没有账号,则注册一个。
注册地址:https://issues.sonatype.org/secure/Signup!default.jspa

Sign up

注册成功之后,记下用户名和密码,在上传jar到Nexus时要用到。
登录Sonatype JIRA,并新建工单:


Create ticket

ticket.png

根据其提示填好对应的内容,提交。

提交之后,平台会给你留言,还会有相应的邮件通知。
告诉你哪里有问题或者接下来该怎么做。如图所示:


comment_1.png

如果有信息需要修改,比如要修改Group Id,改完之后点击工单上方的“response”按钮,以通知平台已修改完毕,平台会再次查验你的信息。
直到平台回复以下类似内容:


comment_success.png

至此,就可以进行下一步,上传jar包。

步骤三:上传jar包

jar包通过gradle脚本上传。
在Android工程的根目录下新建maven_push.gradle文件。
文件内容如下:

apply plugin: 'maven'
apply plugin: 'signing'

def sonatypeRepositoryUrl

def isReleaseBuild() {
    return VERSION_NAME.contains("SNAPSHOT") == false
}
if (isReleaseBuild()) {
    println 'RELEASE BUILD'
    sonatypeRepositoryUrl = hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
            : "https://oss.sonatype.org/service/local/staging/deploy/maven2"
} else {
    println 'DEBUG BUILD'
    sonatypeRepositoryUrl = hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
            : "https://oss.sonatype.org/content/repositories/snapshots"
}

def getRepositoryUsername() {
    return hasProperty('nexusUsername') ? nexusUsername : ""
}

def getRepositoryPassword() {
    return hasProperty('nexusPassword') ? nexusPassword : ""
}

afterEvaluate { project ->
    uploadArchives {
        repositories {
            mavenDeployer {
                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
                pom.groudId = GROUP_ID
                pom.artifactId = POM_ARTIFACT_ID
                pom.version = VERSION_NAME

                repository(url: sonatypeRepositoryUrl) {
                    authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
                }

                pom.project {
                    name POM_NAME
                    packaging POM_PACKAGING
                    description POM_DESCRIPTION
                    url POM_URL

                    scm {
                        url POM_SCM_URL
                        connection POM_SCM_CONNECTION
                        developerConnection POM_SCM_DEV_CONNECTION
                    }

                    licenses {
                        license {
                            name POM_LICENCE_NAME
                            url POM_LICENCE_URL
                            distribution POM_LICENCE_DIST
                        }
                    }

                    developers {
                        developer {
                            id POM_DEVELOPER_ID
                            name POM_DEVELOPER_NAME
                        }
                    }
                }
            }
        }
    }

    signing {
        required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
        println 'Signing archives...'
        sign configurations.archives
    }

    task androidJavadocs(type: Javadoc) {
        source = android.sourceSets.main.java.sourceFiles
        options {
            links "http://docs.oracle.com/javase/7/docs/api/"
            linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
        }
        classpath += project.android.libraryVariants.toList().first().javaCompile.classpath
        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    }

    task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
        classifier = 'javadoc'
        from androidJavadocs.destinationDir
    }

    task androidSourcesJar(type: Jar) {
        classifier = 'sources'
        from android.sourceSets.main.java.sourceFiles
    }

    artifacts {
        archives androidSourcesJar
        archives androidJavadocsJar
    }
}

然后引用maven_push.gradle。
在library module的build.gradle文件的头部或尾部添加:

apply from: '../maven_push.gradle'
步骤四:配置maven信息:

在根目录的的gradle.properties文件中设置POM信息,实例如下:

VERSION_NAME=1.0.2
VERSION_CODE=2
GROUP_ID=com.github.2ndlines 

POM_DESCRIPTION=Android Download Library
POM_URL=https://github.com/2ndLines/XDownloadManager
POM_SCM_URL=https://github.com/2ndLines/XDownloadManager
POM_SCM_CONNECTION=scm:git@github.com:2ndLines/XDownloadManager.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:2ndLines/XDownloadManager.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=Apache 2.0
POM_DEVELOPER_ID=[your id]
POM_DEVELOPER_NAME=[your name]

POM_NAME=Download library
POM_ARTIFACT_ID=download
POM_PACKAGING=aar
WEB_SITE_URL=https://github.com/2ndLines/XDownloadManager
ISSUE_TRACKER_URL=https://github.com/2ndLines/XDownloadManager/issues
VCS_URL=https://github.com/2ndLines/XDownloadManager.git

RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2
SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots

配置信息中的VERSION_NAME如果包含SNAPSHOT,如1.0.2-SNAPSHOT,表示上传快照版本,否则表示上传正式版本。
其中的私有信息请替换成你个人的。

配置GPG信息,用于签署上传的jar或aar文件

如果没有安装gpg,请先进行安装。

$ brew install gpg

生成密钥对(记住签名密码,后面要用):

$ gpg --gen-key

查看公钥Id:

$ gpg --list-key --keyid-format short

例如:
pub rsa2048/F7D94EDD 2019-11-08 [SC] [有效至:2021-11-07] ,
rsa2048后面的F7D94EDD就是公钥Id。
上传公钥Id到公网:

gpg --keyserver hkp://pgp.mit.edu --send-keys  [your_pubkey_id]

生成密钥环文件:

$gpg --export-secret-keys  -o ~/.gnupg/secring.gpg

如果有多套密钥对,则可通过指定uid来导出指定的密钥。例如:

$gpg --export-secret-keys  -o ~/.gnupg/secring.gpg  [your_email@your_domain.com]

配置gpg信息:

##gpg信息
signing.keyId=[your_pubkey_id]
signing.password=[your_signing_password]
signing.secretKeyRingFile=/Users/[your_username]/.gnupg/secring.gpg
##nexus账号信息,也就是创建工单时的账号和密码
nexusUsername=[your_sonatype_account]
nexusPassword=[your_sonatype_password]

至此,就可以通过gradle脚本上传jar到sonatype nexus。
进入Android Studio工程,打开terminal,

$ ./gradlew uploadArchives

指令执行成功,表示上传成功。

步骤五:验证jar,提交审核

完成上一步之后,登录sonatype nexus进行查看,登录账号跟创建工单时注册的账号一致。

  • 如果VERSION_NAME中包含SNAPSHOT,则表示上传的是快照版本,查看位置为:
    snapshot.png

    按groudId路径搜索你的jar时,可能需要等1分钟左右,视网络而定,切莫急躁。
  • 如果VERSION_NAME中不包含SNAPSHOT,则表示上传正式版本。查看路径为:
    release.png

选中上传的文件,然后点击“close”按钮,然后查看下方的activity栏,看看是否有验证错误,如果没有,则点击“release”按钮,并到工单下留言。如果有,可到下方留言,或自行摆渡解决。
工单留言实例如下图所示:

image.png

我在验证release版本时遇到的坑:

  1. failed:signature validation. 签名验证失败,提示信息说缺失*.asc文件。因为我在配置gpg信息时没有配置signing.secretKeyRingFile 。因为我用的gpg版本高于2.1, 不会自行产生secring.gpg文件。

    坑啊

  2. failed:POM validation. POM文件验证失败。因为maven_push.gradle和POM配置信息是从网上找的。刚开始找了一些缺胳膊少腿的。坑啊!!

  3. 我刚把release包上传到nexus,就跑去给Sonatype JIRA留言,结果人家提示我说:


    image.png

    所以我在文章中给出的步骤是jar提交nexus,然后自行查看验证结果无误之后再到JIRA留言,以免浪费时间。

另外,至于为什么是不包含SNAPSHOT则为正式版本,因为maven_push.gradle脚本函数中是这么设定的。也是约定俗成的。

到工单下留言之后,Sonatype JIRA会进行最后审核,通过之后,会收到类似如下留言:


comment_finish.png

愉快的等待2个小时后,到Sonatype中央库搜索你的jar。如果能搜到,则表示已审核通过,成功进入maven中央库。恭喜你!!
以后就可以愉快地“close”和“release”了。

测试你发布到中央库的jar

在module的build.gradle中添加库依赖,例如:

...
dependencies {
    //your other dependencies
    implementation 'com.github.2ndlines:download:1.0.3-SNAPSHOT'
}
...
  • 如果是快照版本,在根build.gradle中添加maven库快照地址:
...
allprojects {
    repositories {
        ...
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots'}
    }
}
...
  • 如果是正式版本,则在根build.gradle中添加maven库地址:
...
allprojects {
    repositories {
        ...
        mavenCentral()
    }
}
...

其实,上传jar中遇到坑都不算坑,真正的坑是jar包里的坑。哈哈哈~
最后,希望更新开发者加入开源阵营,齐力带飞中国的软件开源工程,在开源排行榜上多一些国人的面孔和组织。加油!!


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容