Android庫發佈至MavenCentral流程詳解

歡迎關注微信公衆號:FSA全棧行動 👋html

"jCenter 不久後將中止服務" 這個消息對全部 Android 開發者的影響是很大的,不少好用的第三方庫都會上傳到 jCenter,並且幾乎全部的 Android 項目裏都會依賴到 jCenter 倉庫,這意味着 Android 開發者對其有很強的依賴性。做爲第三方庫使用者來講,一旦到了 jCenter 停服那時,只有 2 種選擇:java

  1. 使用阿里等第三方代理倉庫(上面可能會緩存着這些曾經託管在 jCenter 上的第三方庫)
  2. 祈禱第三方庫做者能早日同步庫到 MavenCentral

如下是其餘人對 jCenter 停服事件的見解文章推薦,有興趣能夠去看看:
《淺談 JCenter 即將被中止服務的事件》android

迴歸主題,若是你是一個第三方庫開發者,且以前沒有上傳庫到 MavenCentral 經驗的話,本文能夠助你早日上傳庫到 MavenCentral~git

1、Sonatype 帳號

一、註冊 Sonatype

MavenCentral 和 Sonatype 的關係至關於 jCenter 和 jForg:github

庫平臺 運營商 管理後臺
jCenter jForg bintray.com
MavenCentral Sonatype oss.sonatype.org

注意:最新管理後臺連接是:s01.oss.sonatype.org,詳情見central.sonatype.org/publish/rel…apache

因此,在上傳庫到 MavenCentral 以前,須要先註冊登陸 Sonatype,訪問 issues.sonatype.org :api

若是你已經有帳號,則直接登陸,不然點擊 Sign up 進入註冊頁面:緩存

填寫好帳號、密碼、郵箱等信息便可註冊成功,註冊成功後再登陸 Sonatype。服務器

注意:郵箱很重要,建議是你經常使用的郵箱,才能及時收到 Sonatype 在 issue 中給你的答覆信息提醒。微信

二、申請上傳權限

如今你已經有 Sonatype 帳號了,接下來理應就是藉助 grdle 腳本經 管理後臺(s01.oss.sonatype.org) 把庫上傳到 MavenCentral ,可是,Sonatype 新用戶默認是沒有這個權限的,不信你能夠訪問 s01.oss.sonatype.org後,點擊右上角 "Log In" 登陸試試看,會提示沒有權限:

注意:出現這個彈窗有 2 種可能,一種是帳號密碼錯誤,另外一種沒有權限。

因此,如今咱們須要讓 Sonatype 給咱們開通這個權限,回到登陸成功後跳轉的那個頁面issues.sonatype.org,點擊頂部的 新建 按鈕,填寫項目信息:

注意:圖中是我我的項目信息,只是舉例,不要照抄!!

這個步驟中,惟一須要注意的地方就是 Group Id,有兩種狀況:

  • 無網站域名:能夠直接使用 github 的子域名 io.github.username,好比個人 github 帳號名是 GitLqr,那麼能夠填寫 io.github.gitlqr
  • 有網站域名:能夠填寫我的或公司域名,好比:com.gitlqr,另外,還須要在 DNS 配置中配置一個 TXT 記錄來驗證域名全部權,具體請看:central.sonatype.org/pages/produ…

注意:目前已經不能再使用 com.github 域名了,具體緣由請看:central.sonatype.org/changelog/#…;使用本身的網站域名時,建議寫頂級域名,不須要具體到某個項目的子域名,如此一來,Group Id 只須要申請一次,之後你的其餘庫都使用同一個 Group Id 便可。

填寫信息後,點擊"新建"按鈕,開啓一個 issue,會顯示 wait for response,等待 Sonatype 工做人員審覈回覆:

由於 Sonatype 是國外運營,因此工做時間上會有時差,咱們須要耐心等待 Sonatype 工做人員處理這個 issue,好比我這樣:

注意:若是你想盡快上傳庫,那麼前面已經提到了,請使用你經常使用的郵箱,當 Sonatype 工做人員評論時,會第一時間經過郵件通知到你。

2、Gradle 配置

首次向 Sonatype 申請上傳權限可能會有點久,咱們能夠同步處理 gradle 配置。

一、Maven 提交腳本

在項目根目錄下新建一個 maven-publish.gradle 文件,內容以下:

注意:如下內容是通用配置,直接拷貝便可。

if (project.hasProperty("android")) { // Android libraries
    task sourcesJar(type: Jar) {
        classifier = 'sources'
        from android.sourceSets.main.java.srcDirs
    }

    task javadoc(type: Javadoc) {
        // https://github.com/novoda/bintray-release/issues/71
        excludes = ['**/*.kt'] // < ---- Exclude all kotlin files from javadoc file.
        source = android.sourceSets.main.java.srcDirs
        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
        options.encoding = "utf-8"
        options.charSet = "utf-8"
    }
} else { // Java libraries
    task sourcesJar(type: Jar, dependsOn: classes) {
        classifier = 'sources'
        from sourceSets.main.allSource
    }
}

// 強制 Java/JavaDoc 等的編碼爲 UTF-8
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

tasks.withType(Javadoc) {
    options.encoding = "UTF-8"
}

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

// add javadoc/source jar tasks as artifacts
artifacts {
    archives javadocJar
    archives sourcesJar
}

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


//Properties properties = new Properties()
//properties.load(project.rootProject.file('local.properties').newDataInputStream())
//
//def ossrhUsername = properties.getProperty("ossrhUsername")
//def ossrhPassword = properties.getProperty("ossrhPassword")

def PUBLISH_GROUP_ID = publishedGroupId //這裏能夠不是直接申請時候的groupId只要開頭是就能夠

def PUBLISH_ARTIFACT_ID = artifact

def PUBLISH_VERSION = libraryVersion // android.defaultConfig.versionName //這個是直接獲取的庫gradle裏配置好的版本號,不用處處修改版本號,只須要維護一份就能夠。

//簽名
signing {
    required { gradle.taskGraph.hasTask("uploadArchives") }
    sign configurations.archives
}

uploadArchives {
    repositories {
        mavenDeployer {

            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

            repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
                authentication(userName: ossrhUsername, password: ossrhPassword)
            }

            snapshotRepository(url: "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
                authentication(userName: ossrhUsername, password: ossrhPassword)
            }

            pom.groupId = PUBLISH_GROUP_ID
            pom.artifactId = PUBLISH_ARTIFACT_ID
            pom.version = PUBLISH_VERSION

            pom.project {
                packaging 'aar' //我這裏發佈的是安卓的包,全部寫的aar

                name libraryName // '發佈庫的簡單名稱'
                // optionally artifactId can be defined here
                description libraryDescription // '發佈包的描述'
                url siteUrl // '能夠寫公司官網地址或github我的頁面地址'

                scm {
                    connection gitUrl // 'scm:替換成項目git地址'
                    developerConnection gitUrl // 'scm:替換爲git開頭的項目地址'
                    url siteUrl // '項目首頁,能夠是github項目的主頁'
                }

                licenses {
                    license {
                        name licenseName // 'The Apache License, Version 2.0'
                        url licenseUrl // 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }

                developers {
                    developer {
                        id developerId // '這裏填寫申請帳號時候的全名就能夠'
                        name developerName // '這裏隨意填寫就能夠'
                        email developerEmail// '最好是申請帳號時用的郵箱'
                    }
                }
            }
        }
    }
}
複製代碼

二、Maven 庫信息配置

庫信息共用兩處配置:

  • 通用信息:填寫在項目根目錄下的 gradle.prperties 文件中。
  • Module 信息:填寫在具體 Module 目錄下的 build.gradle 文件中。

通用信息 gradle.prperties 配置

publishedGroupId=你申請權限時填寫的GroupId
siteUrl=項目url
gitUrl=git連接
developerId=帳號id
developerName=帳號id
developerEmail=郵箱

licenseName=The Apache Software License, Version 2.0
licenseUrl=http://www.apache.org/licenses/LICENSE-2.0.txt
allLicenses=["Apache-2.0"]
複製代碼

具體可參考 github.com/GitLqr/Lite…

Module 信息 build.gradle 配置

ext {
    artifact = '庫的惟一標識'
    libraryName = '發佈庫的簡單名稱'
    libraryDescription = '發佈包的描述'
    libraryVersion = '發佈庫的版本號'
}
複製代碼

具體可參考 github.com/GitLqr/Lite…

三、導入 Maven 腳本

在庫對應的 Module 目錄下的build.gradle文件底部添加以下代碼:

apply from: '../maven-publish.gradle'
複製代碼

在 AS 中 Sync Now 一下 Gradle,就能夠在 Gradle 面板中看到多了一個 upload/uploadArchives 任務了。

3、GPG 簽名

經過以上兩步以後,還差最後一步,此時你運行 uploadArchives 任務是沒法正常提交的,MavenCentral 提交還須要配置 GPG 簽名文件。

一、使用 Gpg4win 生成 GPG 密鑰

注意:如下生成 GPG 密鑰的操做流程使用的是 Window 環境,若是你使用的是 Mac,請參考:www.jianshu.com/p/1c715203c…

先到www.gpg4win.org/get-gpg4win…下載安裝好 Gpg4win:

啓動 Gpg4win,點擊 "文件" - "新建密鑰對...":

建立我的 OpenPGP 密鑰對:

填寫帳號、郵箱,並勾選 Protect the generated key with a passphrase

注意:在高級設置裏能夠設置更詳細的,例如過時時間,但過時時間不能夠太長,或報錯。

點擊 "新建", 設置密碼(確認密碼):

等待生成密鑰後,出現以下彈窗,點擊 "完成":

在主界面雙擊剛剛建立好的密鑰,會出現以下彈窗,須要把底部的那 8 個字符複製下來,在後面的【配置密鑰】環節會用到:

在主界面右擊剛剛建立好的密鑰,點擊 "在服務器上發佈...",而後一路肯定:

在主界面右擊剛剛建立好的密鑰,點擊 "導出...",這時注意了,必定要在這裏先把文件名改爲 "gpg" 或者 "pgp",再點保存:

注意了,Gpg4win 的導出分爲兩種:

  • "導出...": 導出公鑰
  • "Backup Secret Keys": 導出 私鑰 !!

提示:後續步驟須要用到的是 私鑰,因此須要點 "Backup Secret Keys" 導出私鑰的 gpg 文件;導出時默認文件後綴是 "asc",必定要在這時修改後綴爲 "gpg",這樣才能生成正確的 二進制 gpg 密鑰文件。若是先保存成 asc 文本文件,再修改爲 gpg 是沒有用的!!!

二、配置密鑰

這一步很關鍵,須要在電腦 用戶目錄 下的 .gradle/gradle.properties 中配置以下內容:

好比:C:\Users\CharyLin\.gradle\gradle.properties

# MavenCentral
signing.keyId=剛纔獲取的密鑰後8位
signing.password=以前咱們執行命令時設置的密碼
signing.secretKeyRingFile=剛纔生成的gpg文件路徑
ossrhUsername=sonatype用戶名
ossrhPassword=sonatype密碼
複製代碼

4、發佈

一、上傳檔案(uploadArchives)

到了這一步,就能夠去 Gradle 面板中雙擊執行 uploadArchives 任務了,成功的話,會出現以下日誌:

11:12:00: Executing task 'uploadArchives'...

...

> Task :litearouter-api:sourcesJar UP-TO-DATE
> Task :litearouter-api:signArchives UP-TO-DATE
> Task :litearouter-api:uploadArchives

...

BUILD SUCCESSFUL in 16s
23 actionable tasks: 1 executed, 22 up-to-date
11:12:16: Task execution finished 'uploadArchives'.
複製代碼

若是出現 Unable to read secret key from file: it may not be a PGP secret key ring 的錯誤,有如下三種可能:

  • GPG 帳號、密碼有誤
  • 使用的是 GPG 公鑰文件
  • 使用的是 GPG 密鑰文件,可是是先保存成 asc 文件後修改爲 gpg 文件
FAILURE: Build failed with an exception.

* What went wrong:
Could not evaluate onlyIf predicate for task ':litearouter-annotation:signArchives'.
> Unable to read secret key from file: D:\CharyLinDatas\GitLqr\secret.gpg (it may not be a PGP secret key ring)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 11s
複製代碼

二、發佈檔案

如今能夠去登陸下的管理後臺 s01.oss.sonatype.org/, 而後點擊左側的 "Staging Repositories":

選中剛上傳的包, 底部的 Content 選項卡下,能夠看到包內的文件有哪些:

肯定無誤後, 點擊 "Close", 填寫描述信息, 而後點擊 "Confirm":

正常狀況下, 等待幾分鐘後, Activity 選項卡中出現對號的 "Repository closed" 就是 close 成功了:

而後再點擊 "Release" 按鈕便可發佈到 MavenCentral, 等待幾個小時後能夠在 search.maven.org/ 查詢發佈結果。

由於 Release 時勾選了 "Automatically Drop" 選項, 因此當包發佈成功以後會自動從 Staging Repository 中刪除。

須要注意的是, 若是你的庫有好幾個 component, 像個人項目就包含了 litearouter-annotationlitearouter-apilitearouter-compiler 三個, 切記一個一個按流程來, 好比:

  • litearouter-annotation: upload --> close --> release
  • litearouter-api: upload --> close --> release
  • litearouter-compiler: upload --> close --> release

不要一次性所有 upload, 而後又一次性 close, 最後再一次性 release, 這種作法不肯定會帶來什麼後果, 建議不要這樣搞。

5、補充

一、Group Id 是什麼

gradle 中會使用 implementation 來依賴某個第三方庫,結構爲:implementation GroupId:ArtifactId:Version

好比:implementation 'com.android.support:appcompat-v7:27.1.1'

組成部分 解釋
GroupId 是項目組織的惟一標識符,在實際開發中通常對應 JAVA 的包的結構,就是 main 目錄裏 java 的目錄結構,如 ‘com.android.support’。
ArtifactId 是項目的惟一標識符,在實際開發中通常對應項目的名稱,就是項目根目錄的名稱,例:appcompat-v7。
Version 是項目的版本號,例:1.0-SNAPSHOT 。其中 1.0 是版本號,SNAPSHOT 版本表明不穩定、尚處於開發中的版本。而衍生的有 Release 版本則表明穩定的版本

注意:這裏說的是 GroupId 通常 對應包結構,也就是說,GroupId包名 是能夠不同的。就像 Android 項目裏的 applicationId包名 是兩個不一樣的概念同樣。

參考資料

若是文章對您有所幫助, 請不吝點擊關注一下個人微信公衆號:FSA全棧行動, 這將是對我最大的激勵. 公衆號不只有Android技術, 還有iOS, Python等文章, 可能有你想要了解的技能知識點哦~

相關文章
相關標籤/搜索