Androidライブラリを2024/2/1以降にMavenCentralに新しくpublishしたい
背景
久々にMavenCentralに新規ライブラリを新規namespaceにアップロードしようとしたら詰まったのでメモです。
(スクショ撮ったり丁寧に解説してなくてすみません)
公式サイトに一応全て書いてあるが、今までEarly Accessだった自動化されたpublish方式が2024/2/1以降に一般公開されたらしい。
また、今までの方法も段階的に移行予定らしい。
とりあえず、3/12にはjiraでのnamespace承認プロセスはクローズされる予定らしい。
とりあえず新規でnamespaceをとる人以外はしばらくは今まで通りの方法が使えます。
GPGでの署名関連は特に言及しないですが、必要なファイルや環境変数は設定しておいてください。
今までの方法
見たい方用
流れ
- https://issue.sonatype.org (jira)にissueを立てて人と交渉して、namespaceを取得
- https://oss.sonatype.org/ (Nexus repository manger) でバイナリをアップロードしたり、maven形式でのupload(mavenでいうpublish)を行うことで公開準備(staging)ができる。
- oss.sonatype.orgかAPI経由でStagingをclose and releaseすることで maven central repositoryに公開できた
まだドキュメントはあります。
- namespace取得: https://central.sonatype.org/register/legacy/
- upload(maven-publish)方法:https://central.sonatype.org/publish/publish-guide/
- release方法:https://central.sonatype.org/publish/release/#contact-central-support-at-sonatype
gradleでフロー化
Androidはgradleを使っているので、archiveやuploadはgradle経由でやりたい。
だいたい以下のようにやれば良い。
gradle公式のmaven-publishプラグインとsigningプラグインを使用するのが好き。
あと、Nexus repository managerはuploadごに自動publishできないので、publishするためにAPIを叩くところも自動化できると良さそう。
公式には特にpluginは出てませんでした。
今でも動いてるリリースフローのファイルイメージは下記。
(簡略化してたり、groovy製のをktsに直したりしたので動かなかったら直してください)
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("maven-publish")
id("signing")
id("io.codearte.nexus-staging")
}
group = "com.example"
version = "0.0.1"
android {
namespace = "com.example.library"
compileSdk = 34
defaultConfig {
minSdk = 26
}
// ...
publishing {
// AGP 7.1からは下記が使えて便利だけどうまく動かないこともある
singleVariant("release") {
withJavadocJar()
withSourcesJar()
}
}
}
dependencies {
// ...
}
// "release" variantが取得できないとconfigできないから。
afterEvaluate {
publishing {
publications {
register<MavenPublication>("maven") {
groupId = project.group as String
artifactId = "library"
version = project.version as String
from(components["release"])
pom {
name = "xxx"
description = "xxx"
url = "https://github.com/xxx/xxx"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "xxx"
name = "xxx"
email = "xxx@xxx"
}
}
scm {
connection = "scm:git:https://github.com/xxx/xxx.git\""
developerConnection = "scm:git:ssh://github.com/xxx/xxx.git"
url = "https://github.com/xxx/xxx"
}
}
}
}
repositories {
maven {
url = URI("https://oss.sonatype.org/service/local/staging/deploy/maven2")
credentials {
username = "xxx"
password = "xxx"
}
}
}
}
signing {
// 必要に応じてkeyidやpassphraseはpropertiesやenv等で設定
sign(publishing.publications["maven"])
}
}
nexusStaging {
packageGroup = project.group
stagingProfileId = "xxx"
username = "ossrhUsername"
password = "ossrhPassword"
}
実行イメージ
# maven-publishを行う。
$ ./gradle publish
# Nexus repository managerでstagingされたものをreleaseする
$ ./gradlew closeAndReleaseRepository
でもこれはそのうち廃止されるかもしれない。
2024/2/1以降の方法
流れ
- https://central.sonatype.com/ (昔のbintray的なツール)でアカウント作成してnamespace取得まで自動でできる
- https://central.sonatype.com/ でpublishを作成してバイナリをアップロードしたり、maven形式のファイルをAPI経由でupload
- uiからやった場合や自動publishしなかった場合はUIかAPI経由でpublishリクエスト
ドキュメント
- アカウント、namespace取得: https://central.sonatype.org/register/central-portal/
- zipの作り方:https://central.sonatype.org/publish/publish-portal-upload/
- API経由でのuploadやpublish方法:https://central.sonatype.org/publish/publish-portal-api/
gradleでフロー化
すでに書かれていますが、Android版じゃないので補足的に書きます。
今度は公式のgradle plugin作ってくれるぽいこと書いてるのでひっそりと期待します。
やっぱり、gradle公式のmaven-publishプラグインとsigningプラグインを使用するのが好きなのでそうしてます。
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("maven-publish")
id("signing")
}
group = "com.example"
version = "0.0.1"
android {
// ...
publishing {
singleVariant("release") {
// withJavadocJar() // こっちだとsigningに間に合わないので諦めて空にする
withSourcesJar()
}
}
}
dependencies {
// ...
}
// 空のjavadocjarを生成するタスク
tasks.register<Jar>("javadocEmptyJar") {
archiveClassifier = "javadoc"
}
// uploadするためのzipを生成するタスク
tasks.register<Zip>("makeArchive") {
dependsOn("publishMavenPublicationToMavenRepository")
from(layout.buildDirectory.dir("repos/com/example/library/$version"))
into("com/example/library/$version")
}
afterEvaluate {
publishing {
publications {
register<MavenPublication>("maven") {
groupId = project.group as String
artifactId = "library"
version = project.version as String
from(components["release"])
artifact(tasks["javadocEmptyJar"])
pom {
name = "xxx"
description = "xxx"
url = "https://github.com/xxx/xxx"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "xxx"
name = "xxx"
email = "xxx@xxx"
}
}
scm {
connection = "scm:git:https://github.com/xxx/xxx.git\""
developerConnection = "scm:git:ssh://github.com/xxx/xxx.git"
url = "https://github.com/xxx/xxx"
}
}
}
}
repositories {
maven {
// 本当はmavenLocalで良いはずだが、checksumファイルが生成されず怒られるので別ディレクトリにpublish
url = uri(layout.buildDirectory.dir("repos"))
}
}
}
signing {
// 必要に応じてkeyidやpassphraseはpropertiesやenv等で設定
sign(publishing.publications["maven"])
}
}
雑な解説
javadocについて
AGP 7.1以降に追加された withJavadocJar はartifactsにjavadocJarを追加してくれるので便利だが、内部でdokkaを使用してるぽく、非同期になるからかsigningされなかった。
そのため、普通にdokka等で生成するか空のjarを含めれば良い。
このサンプルは空のjarにしている。(未公開API等で空にするのは許されているが、別に推奨しないです)
upload用のzip作成
maven-publishプラグインでもuploadできるかもしれないが、試してないです。
公式には別エンドポイントとなっているぽいので、一度zip化するタスクを用意しています。
最初はmavenLocalへpublishしてからzipしてましたが、mavenLocalだとchecksumファイルが生成されなくて怒られるので、一度build/配下にpublishしてzipにしています。
実行イメージ
# localにmaven-publishしてupload用のzipを作る
$ ./gradlew makeArchive
# Central Portalにuploadしてpublishする
# 認証用 keyの生成
$ echo "username:password" | base64
xxx
$ curl --request POST \
--verbose \
--header 'Authorization: Bearer xxx' \
--form bundle=@library/build/distributions/library-0.0.1.zip \
'https://central.sonatype.com/api/v1/publisher/upload?publishingType=AUTOMATIC'
curlやbase64部分はgradle taskとしても良さそうです。
野良プラグインでも良いと思います。
最後のupload時にpublishingTypeは無指定時はautoになる、とドキュメントに書かれていましたが、自動でpublishされなかったため、明示したほうが良さそうです。
感想
新しいcentral portalは今まで下記の点で改善してそうと思いました。
- jiraやnexusでツールが分割されてない
- namespace認証が自動化されている
- upload時に自動publishが選べる
- 結果を取得できるwebhook機能がある?
たくさん進歩があっていいですね!(でも廃止されたjcenter, bintrayに近くなったなという印象ですw やっと追いついた?)
でも、gradleユーザ的にはpluginがなく情報がイマイチまとまっていないので、改善するといいなと思いました。
あとは既存のツールを利用したユーザも移行されていくらしいので、そこはスムーズになるといいと願っています。
Discussion