釋出到 Maven Central 相關的教程挺多的,但是大部分存在問題。這篇文章是我在解決了很多問題的基礎之上總結的,用來幫助需要的同學避免重蹈覆徹。需要的可收藏,萬一用到了呢~
1、Farewell to Bintray jCenter
首先,告别下 bintray jcenter. 相比于 Maven Central,bintray jcenter 的性能和友善性确實好得多。可惜,jcenter 将要關閉了。jcenter 還是給我提供了很多的便利,對于其關閉深表可惜:
2、釋出到 Maven Central
Step 1: 注冊和激活 sonatype
釋出到 Maven Central 之前,首先要到 sonatype 注冊一個賬号,
https://issues.sonatype.org/
新增賬號完賬号之後需要通過建立 issue 激活賬号,頁面如下:
這裡有幾個需要注意的地方:
- 項目選擇 Community Support - Open Source Project Repository Hosting
- 問題類型選擇 New Project
- 概要:描述項目功能,不重要
- Group Id 比較重要,我們後續說明
- Project URL 填寫自己開源項目位址即可,要與 Group Id 有一定的關聯性
- SCM url 版本倉庫的拉取位址,填寫自己的項目的 git 連結位址,通常是項目位址後加
.git
對于這裡的 group id,它就是釋出完成之後,引用時的 group id. 你可以使用自己的域名,但是需要證明域名是你自己的。如果沒用自己的域名,一個簡單而通用的方式是使用 Github 的位址,比如我的 GitHub 位址是 https://github.com/Shouheng88 ,就可以寫作 com.github.Shouheng88. 建立完 issue 之後幾分鐘内就會收到對方發送的郵件,郵件内會提示通過在 Github 裡面建立項目來驗證激活:
當我們按照郵件說明建立完項目之後,修改問題狀态,過幾分鐘之後就激活成功了。
Step 2: 申請密鑰
為了確定中央存儲庫中可用元件的品質水準,OSSRH 對送出的檔案有明确的要求。除了 jar 包和 pom 檔案,Javadoc 和 Sources 是必須的(這點和 bintray jcenter 類似),并且每個檔案都要有一個對應的 asc 檔案,即 GPG 簽名檔案,用于校驗檔案。是以,這步驟中我們需要申請密鑰。
OSX 下面可以使用 brew 安裝,
$ brew update
$ brew install -v gpg
Windows 下面也可以直接下載下傳安裝,
https://www.gpg4win.org/get-gpg4win.html
安裝完畢之後,可以通過如下指令生成密鑰:
gpg --generate-key
建立密鑰的過程中會要求輸入密碼,這裡的密碼非常重要,我們釋出的時候會使用到它。
建立完畢之後可以通過
gpg -k
顯示所有已建立的密鑰:
這裡的字元串
AB7FxxxxxxxxxxxxABA846D44F7B66
叫做密鑰指紋。後面 8 位 D44F7B66,叫做 KEY ID,我們釋出的時候将使用到它。
另外,進行檔案簽名的時候需要用到名為 secretKeyRingFile 的檔案,我們可以通過如下指令生成:
gpg --export-secret-keys [密鑰指紋] > secret.gpg
在 sonatype 的倉庫送出後,需要從多個公鑰伺服器上下載下傳比對的公鑰,然後來校驗你上傳的檔案的簽名。是以,我們需要通過下面的指令上傳公鑰到公鑰伺服器:
gpg --keyserver keyserver.ubuntu.com --send-keys [密鑰指紋]
Step 3: 準備釋出腳本
首先需要引入兩個插件,
apply plugin: 'maven-publish'
apply plugin: 'signing'
然後編寫釋出的 gralde 腳本如下
task androidSourcesJar(type: Jar) {
archiveClassifier.set("sources")
from android.sourceSets.main.java.source
exclude "**/R.class"
exclude "**/BuildConfig.class"
}
publishing {
publications {
mavenJava(MavenPublication) {
// group id,釋出後引用的依賴的 group id
groupId 'com.github.Shouheng88'
// 釋出後引用的依賴的 artifact id
artifactId 'sil'
// 釋出的版本
version '0.1.0'
// 釋出的 arr 的檔案和源碼檔案
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
artifact androidSourcesJar
pom {
// 構件名稱,可以自定義
name = 'uix-common'
// 構件描述
description = 'Android UIX'
// 構件首頁
url = 'https://github.com/Shouheng88/Android-uix'
// 許可證名稱和位址
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
// 開發者資訊
developers {
developer {
name = 'ShouHeng'
email = '[email protected]'
}
}
// 版本控制倉庫位址
scm {
url = 'https://github.com/Shouheng88/Android-uix'
connection = 'scm:git:github.com/Shouheng88/Android-uix.git'
developerConnection = 'scm:git:ssh://[email protected]/Shouheng88/Android-uix.git'
}
}
}
}
repositories {
maven {
// 釋出的位置,這裡根據釋出的版本區分了 SNAPSHOT 和最終版本兩種情況
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 {
// 這裡就是之前在 issues.sonatype.org 注冊的賬号
username ossrhUsername
password ossrhPassword
}
}
}
}
signing {
sign publishing.publications
}
注意:這裡的 group id 必須和申請的 sonatype 申請賬号時申請的 group id 一緻。這裡的要釋出到的倉庫的位址可能是每個使用者不同的,具體是多少要看檢視自己的激活郵件(可檢視下面的“到 Sonatype 處理釋出結果”小節)。
此外,我們需要在 gradle.properties 中定義我們的賬戶相關的資訊:
signing.keyId=密鑰keyId
signing.password=密鑰password
signing.secretKeyRingFile=私鑰keyRingFile路徑
sonatypeUsername=sonatype賬号
sonatypePassword=sonatype密碼
Step 4: 釋出
配置完成之後釋出就比較簡單了,隻需要在 AS 的右邊欄的 gradle 工作列裡指定的 module 下面選擇 publishing 任務,然後選擇
publishMavenJavaPublishingToMavenRepository
即可:
Step 5:到 Sonatype 處理釋出結果
實際上每個使用者釋出到的分區可能是不同的,一個準确的檢視的方法是,當你完成賬号激活之後會收到一封郵件,這裡寫明了你的檔案釋出到的位置,
比如我的在 https://s01.oss.sonatype.org 域名下,而其他使用者的可能在 https://oss.sonatype.org/ 域名下,如果我用自己注冊的賬号登入其他的域名就會報權限相關的錯誤,這裡也是一個坑。
登入到自己的倉庫之後點選左側的
Staging Repositories
就可以看到我們剛剛釋出的檔案。
勾選我們的檔案之後點選 Close,snoatype 将對我們釋出的檔案進行校驗,校驗需要一分鐘左右的時間,校驗完畢之後點選 Release,就最終釋出了我們的檔案。
Step 6: 引用我們的庫
釋出完成之後就可以引用了,引用依賴的方式和其他倉庫完全一樣,需要說明的是,需要先添加 Maven Central 的倉庫的位址:
repositories {
//推薦: release成功後會直接從mavenCentral拉取aar
mavenCentral()
//或者
maven {url "https://s01.oss.sonatype.org/content/groups/public"}
//或者
maven {url "https://s01.oss.sonatype.org/content/repositories/releases"}
}
Step 7: 處理引用的問題
我發現大部分教程都是介紹到上面就結束了,但是實際上還有很重要的一個步驟需要解決。
通常我們的庫并不是獨立的,它可能通過各種方式引用其他的庫,比如 implementation、api、compile 或者 compileOnly 等。使用 Bintray Jcenter 的時候,它可以自動根據我們項目的依賴關系生成 pom 檔案中的依賴。但是釋出到 Maven Central 的時候需要我們自己解決這個問題。如果不解決這個問題,引用的時候就隻引用到了我們自己釋出的這個 aar 檔案。這顯然是不行的。
我通過對比 Bintray JCenter 對各種引用方式,編寫了下面的代碼用來生成 pom 中的依賴關系:
withXml {
def dependenciesNode = asNode().appendNode('dependencies')
project.configurations.all { configuration ->
def name = configuration.name
if (name != "implementation" && name != "compile" && name != "api") {
return
}
println(configuration)
configuration.dependencies.each {
println(it)
if (it.name == "unspecified") {
// 忽略無法識别的
return
}
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
if (name == "api" || name == "compile") {
dependencyNode.appendNode("scope", "compile")
} else { // implementation
dependencyNode.appendNode("scope", "runtime")
}
}
}
}
這裡會先對引用的方式做一個判斷,然後根據引用的方式選擇對應的 scope,同時處理了一些異常的情況。
最終的釋出腳本
task androidSourcesJar(type: Jar) {
archiveClassifier.set("sources")
from android.sourceSets.main.java.source
exclude "**/R.class"
exclude "**/BuildConfig.class"
}
publishing {
// 定義釋出什麼
publications {
mavenJava(MavenPublication) {
// group id,釋出後引用的依賴的 group id
groupId 'com.github.Shouheng88'
// 釋出後引用的依賴的 artifact id
artifactId 'sil'
// 釋出的版本
version '0.1.0'
// 釋出的 arr 的檔案和源碼檔案
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
artifact androidSourcesJar
pom {
// 構件名稱,可以自定義
name = 'uix-common'
// 構件描述
description = 'Android UIX'
// 構件首頁
url = 'https://github.com/Shouheng88/Android-uix'
// 許可證名稱和位址
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
// 開發者資訊
developers {
developer {
name = 'ShouHeng'
email = '[email protected]'
}
}
// 版本控制倉庫位址
scm {
url = 'https://github.com/Shouheng88/Android-uix'
connection = 'scm:git:github.com/Shouheng88/Android-uix.git'
developerConnection = 'scm:git:ssh://[email protected]/Shouheng88/Android-uix.git'
}
// 解決依賴關系
withXml {
def dependenciesNode = asNode().appendNode('dependencies')
project.configurations.all { configuration ->
def name = configuration.name
if (name != "implementation" && name != "compile" && name != "api") {
return
}
println(configuration)
configuration.dependencies.each {
println(it)
if (it.name == "unspecified") {
// 忽略無法識别的
return
}
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
if (name == "api" || name == "compile") {
dependencyNode.appendNode("scope", "compile")
} else { // implementation
dependencyNode.appendNode("scope", "runtime")
}
}
}
}
}
}
}
// 定義釋出到哪裡
repositories {
maven {
// 釋出的位置,這裡根據釋出的版本區分了 SNAPSHOT 和最終版本兩種情況
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 {
// 這裡就是之前在 issues.sonatype.org 注冊的賬号
username ossrhUsername
password ossrhPassword
}
}
}
}
signing {
sign publishing.publications
}
總結
以上是一個簡單的解決方案,經過上述操作已經可以幫助我們解決釋出過程中的許多問題。當然,這裡還是有可以優化的空間,比如處理項目依賴等各種情況。
希望本文對你有所幫助,如有疑問可在下方留言。