안드로이드 모듈을 Maven 배포(sonatype을 이용) 방법을 알아보자.



개인 광고 영역

2016년에 JCenter 배포하는 방법을 정리했었는데, jcenter는 사라졌습니다.

이제 Maven을 통한 모듈 배포가 가능한데, JCenter가 쉽게 접근할 수 있는 반명 Maven은 배포하려면 준비해야 할 것들이 많습니다.

이 글에서는 지라 티켓 등록부터 MavenCentral 배포한 결과물까지 살펴보려고 합니다.

필자의 경우 배포한 모듈은 Retrofit FlowCallAdapterFactory입니다. Retrofit에서 Flow을 바로 사용하기 위한 모듈입니다.

Retrofit-FlowCallAdapterFactory

이 글에서 알아볼 내용

  • 모듈을 생성하는 내용은 담지 않습니다.
  • 모듈을 배포하기 위해 사용했던 sonatype Nexus repository 사용 방법을 간단하게 다룬다.
  • 배포를 위한 준비 과정 및 배포 코드(gradle.kts)를 담는다.
  • 배포를 위한 과정을 담지만, 사용한 기술에 대한(kotlin precompiled을) 설명하는 부분은 없습니다.

배포 준비

이 글에서는 배포를 위한 준비로 안드로이드 모듈과 sonatype을 통한 배포 과정을 담습니다.

  1. 모듈을 준비합니다.(여기서는 모듈 생성 과정은 제외하고 설명합니다.)
  2. 모듈 배포를 위한 지라 티켓 등록
  3. 지라 승인이 나야 sonatype의 Nexus repository에 접근할 수 있습니다.
  4. 배포를 위한 maven-publish, signing 라이브러리를 활용해, 배포 스크립트를 작성합니다.
  5. 배포를 위한 GPG 발행 및 서버로의 등록이 필요합니다.
  6. 지라 계정과 GPG 정보를 활용해 스크립트에 계정 정보를 추가로 작성합니다.
  7. 배포를 위한 gradlew 명령어를 입력합니다.
  8. sonatype stagingRepositories에 잘 올라갔는지 확인합니다.
  9. sonatype stagingRepositories close and publish을 진행합니다.
  10. Maven Central repository search에서 내 모듈이 잘 배포되었는지 확인합니다.

과거 JCenter에 비해 매우 많은 과정을 거쳐야 합니다. 지라 티켓 등록부터 진행해야 하며, 자신의 도메인을 가진 경우라면 도메인 인증을 TXT로 등록도 해야 합니다.

이 글에서는 1번 모듈 준비 과정을 제외하고, 배포를 위한 단계를 순서대로 정리해 보려고 합니다.

단, 이 글 작성 시점에만 잘 동작하고, 또한 환경에 따라 동작하지 않을 수 있으니, 참고 글을 미리 공유해 드립니다.

관련 글 참고

이 블로그에서 지라 티켓 부분을 확인할 수 있었습니다.

gradle.kts로 정리되어 있는 글입니다. 필자의 경우 kts를 다루어야 해서 대부분의 코드는 여기를 참고했습니다.

skydoves님의 도움으로 stream.io의 글을 참고했습니다.


2. 모듈 배포를 위한 지라 티켓 등록

maven 배포를 위해서는 지라 티켓부터 등록해야 합니다.

sonatype 지라 티켓 발행을 위해 사이트에 접근하셔서 계정 가입을 먼저 해주세요.

image_01

가입 후 로그인 정보는 Username, Password로 접근할 수 있습니다.(이메일이 아닙니다.)

가입 후 새로운 지라 티켓을 생성해야 합니다. 지라를 많이 사용해 보셨다면 쉽겠지만 처음 사용하셨다면 메인 화면의 상단에 Create 버튼을 눌러주세요.

image_02

총 7개를 작성해 주셔야 합니다.

  1. Project

필수로 선택해야 하는데, 내가 어떤 작업을 진행할 것이라는 프로젝트입니다. 여기서는

Community Support - Open Source Project Repository Hosting (OSSRH)

을 선택해 주시면 됩니다.

  1. Issue type

1번을 OSSRH로 끝나는 값을 선택하셨다면 New Project가 노출되고, New Project를 눌러주시면 됩니다.

  1. Summary
  2. Description

3번과 4번은 배포할 모듈의 제목과 내용을 적어주시면 됩니다. 어떤 내용을 담고 있다는 정보를 설명에 추가하시면 됩니다.

  1. Group Id

배포에 사용할 group ID를 적어주시면 됩니다. group ID는 안드로이드 패키지 명칭과 동일합니다. 단, 자신의 도메인을 사용하겠다면 생성한 티켓의 정보를 도메임 네임 서버에 TXT로 등록하는 절차로 인증하는 과정이 필요합니다.

이 부분에 대한 인증 절차는 sonatype에서 만들어둔 봇이 자동으로 안내하게 됩니다.

  1. Project URL

프로젝트가 이미 github에 올라가 있어야 합니다. 자신의 도메인이 있다면 도메인을 github에 붙여주셔도 좋습니다.

  1. SCM url

.git을 통해 소스코드 접근 가능한 URL을 남겨주시면 됩니다.

지라 과정은 Open > RESOVED 과정을 거치게 되는데, 준비가 안 되어있다면 대기 상태로 돌리게 됩니다.

제가 사용한 Jira 정보가 궁금하시면 OSSRH-76565을 참고하세요.


도메인 확인 방법

도메인 확인 방법은 크게 2가지로 나뉩니다.

개인 도메인 : 본인 소유를 증명하기 위해 DNS TXT에 방금 생성한 지라 티켓 번호를 적어줍니다.

io.github.계정명 도메인 사용 : github에 저장소 이름을 티켓 번호로 임의 생성하여 인증

image_03

결국 2가지 모두 인증 과정을 거쳐야 하는데, 지라 티켓에 봇이 자동으로 달아줍니다.

이 인증 과정을 거쳐야 만 RESOVED 처리를 해줍니다.

자신의 도메인 관리 사이트에 아래와 같은 정보를 저장해 줍니다.

참고 페이지 : How do I set the TXT record needed to prove ownership of my Web Domain?

image_04

그리고 터미널에서 아래 명령을 통해 티켓 번호가 노출되는지 확인하고, OPEN 상태로 변경하고, 커멘트를 남겨주면 OPEN 상태로 변경됩니다.

명령어 : host -t txt thdev.tech
응답 : thdev.tech descriptive text "OSSRH-티켓 번호"

image_05


3. 지라 RESOVED 처리 후 Nexus 접근

지라 RESOVED 처리 후에 Nexus repository manager에 접근할 수 있습니다.

로그인은 지라에 회원 가입 시 사용한 계정과 비밀번호를 입력하시면 됩니다.(Username, Password)

image_06

로그인하시면 아래와 같이 생겼는데, 본 화면에서 사용할 메뉴는 아래 빨간색 네모 부분 정도가 되겠습니다.

나머지 메뉴는 하나씩 눌러보시면 됩니다.

image_07

배포를 위한 사전 단계가 끝났습니다. 하지만 아직 코드 작성 부분과 GPG 키 발행 부분이 남았습니다.


4. 배포를 위한 maven-publish, signing 라이브러리를 활용해, 배포 스크립트를 작성합니다.

이 부분에 대한 다양한 코드들이 존재하지만 필자가 원하는 코드는 딱 gradle.kts를 이용하는 방법입니다.

Sonatype에서 제공하는 gradle을 참고할 수 있도록 코드를 제공해 주고 있습니다.

하지만 좀 더 검색하면 정말 다양한 방법을 제공함을 알 수 있는데

방법은 많지만 정말 다 잘 동작하는지는 상황에 따라 다를 것 같습니다. 아마 제가 작성한 방법도 하나의 방법일 뿐 실제 동작하지 않을 수 있으니, 다양하게 참고하셔야 합니다.

저는 아래와 같은 방법으로 접근하였습니다.

  • 코틀린 문법을 활용하고, buildSrc 하위 폴더에 script를 만들어 사용합니다.
  • script로 접근하다 보니 kotlin-dslkotlin-dsl-precompiled-script-plugins을 플러그인으로 활용합니다. buildSrc/build.gradle.kts 참고
  • lib-publish.gradle.kts를 생성하고, 여기에 script를 작성합니다. buildSrc/base/lib-publish.gradle.kts
  • 작성한 라이브러리는 사용할 모듈에 plugins에 등록하고, 기본 정보 몇가지를 작성합니다. module/build.gradle.kts

제가 작성한 코드 대신 Android에서 제공하는 Use the Maven Publish plugin을 사용할 수 있습니다.


lib-publish.gradle.kts 작성

이 코드는 android library와 maven-publish, signing 플러그인을 활용합니다.

아래와 같이 작성한 이유는 나중에 가져다 쓸 때 id("lib-public")으로 바로 사용할 수 있어서입니다.

이 글에서는 dsl의 precompiled-script-plugins 적용 방법은 다루지 않습니다.

긴 코드라서 필요한 부분에 주석을 달아보겠습니다.

전체 코드는 buildSrc/base/lib-publish.gradle.kts

플러그인 설정

plugins에 아래 3가지 옵션을 추가합니다.

plugins {
    id("com.android.library")
    id("maven-publish") // 배포를 위한 모듈
    id("signing") // 서명을 위한 모듈
}

키 정보를 담기 위한 extra 배열 생성

이 정보는 local.properties 또는 PATH에 등록해두고 사용하도록 하셔야 합니다. 개인 키를 취득할 수 있는 중요한 정보이므로, 절대 외부 공개되어선 안됩니다.

그리고 GPG 키 생성에서 필요한 정보가 3가지가 있습니다. 이는 5번 부분을 참고하시면 됩니다.

// Stub secrets to let the project sync and build without the publication values set up
ext["signing.keyId"] = "" // GPG 키를 생성하고 나온 keyId - 5번의 GPG 키 생성 후 local.properties에 등록
ext["signing.password"] = "" // GPG 키를 생성할 때 적어준 비밀번호 - 5번의 GPG 키 생성 후 local.properties에 등록
ext["signing.key"] = "" // GPG 키 생성 후 BASE64를 한 키값
// key 값의 경우 찾아보는 문서마다 어디서는 파일을, 어디서는 키값을 복붙 하도록 할 수 있습니다. 여기서는 키값을 그냥 붙여 넣어서 쓰겠습니다.
ext["ossrhUsername"] = "" // 지라 가입 시 사용한 Username
ext["ossrhPassword"] = "" // 지라 가입 시 사용한 Password

소스 정보 등록을 위한 registering 등록

이 정보는 압축 파일에 어떠한 정보를 담을 것인지를 사전 정의합니다.

javadoc와 sources를 포함합니다.

val javadocJar by tasks.registering(Jar::class) {
    archiveClassifier.set("javadoc")
}

val androidSourceJar by tasks.registering(Jar::class) {
    archiveClassifier.set("sources")
    from(android.sourceSets.getByName<AndroidSourceSet>("main").java.srcDirs)
}

사용하기 편하게 함수 생성

extra 정보를 쉽게 가져오기 위한 확장 함수입니다.

fun getExtraString(name: String) = ext[name]?.toString()

groupId 지정

이 함수 중 groupId 함수는 지라 티켓 생성 시에 사용한 groupId를 동일하게 지정하셔야 합니다.

fun groupId(): String = "tech.thdev"

코드 시작

lib-publish.gradle.kts에서 코드 작성을 위한 시작 부분입니다.

afterEvaluate {

local.properties에서 정보 가져와 처리하기

이 부분이 앞에서 정의한 ext에 값을 채워주는 부분입니다. local.properties에 정의되어 있는 정보를 차곡차곡 매핑해주거나, PATH 등록한 정보를 가져옵니다.

둘 중 어느 거든 사용하시면 됩니다.

// Grabbing secrets from local.properties file or from environment variables, which could be used on CI
val secretPropsFile = project.rootProject.file("local.properties")
if (secretPropsFile.exists()) {
    secretPropsFile.reader().use {
        Properties().apply {
            load(it)
        }
    }.onEach { (name, value) ->
        ext[name.toString()] = value
    }
} else {
    // Use system environment variables
    ext["ossrhUsername"] = System.getenv("OSSRH_USERNAME")
    ext["ossrhPassword"] = System.getenv("OSSRH_PASSWORD")
    ext["signing.keyId"] = System.getenv("SIGNING_KEY_ID")
    ext["signing.password"] = System.getenv("SIGNING_PASSWORD")
    ext["signing.key"] = System.getenv("SIGNING_KEY")
}

publishing 정보 시작

sonatype repository 배포 정보를 담기 위한 정보를 지정합니다.

// Set up Sonatype repository
publishing {

다시 변수로 값을 담아두자

필요한 정보를 다시 변수로 만들어 두었습니다. getExtraString에 이름을 넘겨주면 다시 맵핑 후 꺼내게 됩니다.

잘 동작하는지가 궁금하시다면 println()으로도 확인이 가능합니다.

val artifactName = getExtraString("libraryName") ?: name
val libraryVersion = getExtraString("libraryVersion") ?: "DEV"
val artifactDescription = getExtraString("description") ?: ""
val artifactUrl: String = getExtraString("url") ?: "http://thdev.tech/"

repositories에 정보 채우기

repositories에 정보를 채워보겠습니다. maven을 사용할 것이니 maven으로 한 번 더 걸고, name, url을 작성합니.

url 정보는 sonatype 지라에서 제공한 정보를 참고하시면 되는데 현재는 아래와 같습니다.

https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/

credentials에 자신의 자리 Username, Password 정보를 지정해 줍니다.

// Configure maven central repository
repositories {
    maven {
        name = "sonatype"
        setUrl("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
        credentials {
            username = getExtraString("ossrhUsername")
            password = getExtraString("ossrhPassword")
        }
    }
}

이 정보는 MavenPublication에서 사용할 정보로 pom 정보를 포함합니다.

어떠한 내용의 압축된 코드를 가져올지, docs를 담을지를 지정하고, 배포할 라이브러리의 라이센스 정보와 개발자 정보를 담게 됩니다.

artifactId의 경우 라이브러리 이름을 사용하는데 보통 -가 붙은 형태를 사용합니다. 제가 배포한 라이브러리 이름은 flow-call-adapter-factory이므로 groupId와 합쳐지면 아래와 같습니다.

tech.thdev:flow-call-adapter-factory:version

version은 현재 배포할 버전을 지정해 주시면 됩니다. 보통 1.x.x로 시작하지만 0.x.x 또는 alpha, beta를 운영하기도 합니다.

// Configure all publications
publications {
    create<MavenPublication>("release") {
        groupId = groupId()
        artifactId = artifactName // 배포할 라이브러리의 이름을 지정합니다. 보통 -로 처리되어 있는 라이브러리명입니다.(안드로이드 라이브러리나 외부 라이브러리를 참고하세요.)
        version = libraryVersion // 배포할 현재 버전 정보를 지정합니다.

        // library 종류에 따라 바라보는 components를 구분합니다.
        if (project.plugins.hasPlugin("com.android.library")) {
            from(components.getByName("release"))
        } else {
            from(components.getByName("java"))
        }

        // Stub android
        artifact(androidSourceJar.get()) // androidSource를 지정합니다.
        // Stub javadoc.jar artifact
        artifact(javadocJar.get()) // javadoc를 지정합니다.

        // Provide artifacts information requited by Maven Central
        pom {
            name.set(artifactName)
            description.set(artifactDescription) // pom 정보에 설명을 추가합니다.
            url.set(artifactUrl)

            licenses {
                license {
                    name.set("The Apache License, Version 2.0")
                    url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
                }
            }
            developers {
                developer {
                    id.set("taehwandev")
                    name.set("taehwan")
                    email.set("[email protected]")
                }
            }
            scm {
                url.set(artifactUrl) // 사이트 주소
            }
        }
    }
}

위에서 지정한 정보는 [https://search.maven.org/artifact/tech.thdev/flow-call-adapter-factory/1.0.0/aar]의 왼쪽 xml 형태로 볼 수 있습니다.

디지털 서명을 위한 signing 라이브러리를 활용합니다.

참고하시는 문서에 따라 이 부분이 존재하지 않을 수 있지만, 저는 stream.io 문서를 참고하여 추가하였습니다.

key를 직접 지정한 이유도 있습니다.


// Signing artifacts. Signing.* extra properties values will be used
signing {
    useInMemoryPgpKeys(
        getExtraString("signing.keyId"),
        getExtraString("signing.key"),
        getExtraString("signing.password"),
    )
    sign(publishing.publications)
}

여기까지가 배포를 위한 코드 준비입니다. 하지만 아직 하나 더 남았습니다.


5. 배포를 위한 GPG 발행 및 서버로의 등록이 필요합니다.

인증을 위한 GPG 키 발행을 하고, signing.keyId, signing.key, signing.password를 작성해야 합니다.

이 3개의 값을 처리하기 위해서 GPG를 발행하고, ubuntu 서버에 배포도 해야 합니다.

sonatype에서 제공하는 문서보다는 stream.io에서 제공한 문서가 더 필요한 정보를 잘 담고 있습니다.

이 문서를 참고해 GPG 키를 발행하고, ubuntu 서버에 등록하는 과정까지 거치고 나서, local.properties에 정보를 채워보도록 하겠습니다.

GPG 설치하기

GPG 인증키를 발행하기 위해서는 GPG 설치부터 해야 합니다. 이 글에서는 mac + brew(homebrew 설치는 링크 참고https://brew.sh/)를 사용한다는 조건하에 설명합니다.

brew를 사용하고 있다면 아래와 같이 gnupg2를 설치합니다.

brew install gnupg2

gpg 생성

터미널에서 아래 명령어를 입력합니다. 여기에서 설정을 진행해 주셔야 합니다.

gpg --full-gen-key

명령어를 실행하면 키 선택을 해주셔야 하는데 1번을 입력하고 엔터를 눌러줍니다.

✘ taehwankwon  ~  gpg --full-gen-key
gpg (GnuPG) 2.3.4; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
  (1) RSA and RSA
  (2) DSA and Elgamal
  (3) DSA (sign only)
  (4) RSA (sign only)
  (9) ECC (sign and encrypt) *default*
 (10) ECC (sign only)
 (14) Existing key from card
Your selection? 1

이번엔 keysize를 지정하는데, 4096을 적어주고 엔터를 눌러줍니다.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096

키의 유효기간을 지정합니다. 여기서는 기본 값인 0과 엔터를 눌러줍니다.

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0

key 만료되지 않는다는 문구에 y와 엔터를 눌러줍니다.(아마 만료가 필요하다면 바로 위 지정부터 다르게 하시면 됩니다.)

Key does not expire at all
Is this correct? (y/N) y

키에 대한 정보를 추가합니다. 이름, 이메일, Comment를 적어줍니다. 그리고 변경할 사항이 없다면 대문자 O를 입력하고 엔터를 눌러줍니다.

GnuPG needs to construct a user ID to identify your key.

Real name: thdev
Email address: [email protected]
Comment: Example key
You selected this USER-ID:
    "thdev (Example key) <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

이제 비밀번호는 최초 입력과 재확인을 요청합니다.

image_08

비밀번호 입력과 재확인 절차가 끝나면 키 발행되고, 이 키에 대한 정보가 노출됩니다.

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: revocation certificate stored as '/Users/taehwankwon/.gnupg/openpgp-revocs.d/535C8DE7E3B561DAAEE384FFF516D0F8912ABC12.rev'
public and secret key created and signed.

pub   rsa4096 2021-12-26 [SC]
      535C8DE7E3B561DAAEE384FFF516D0F8912ABC12
uid                      thdev (Example key) <[email protected]>
sub   rsa4096 2021-12-26 [E]

자신의 ~ 폴더 아래 .gnupg 폴더 아래에 생성됩니다.

이렇게 생성된 키는 ubuntu 서버에 등록해 주어야 하는데, 우선 그전에 local.properties에 필요한 2개 정보를 얻었습니다.

pub 2번째 라인에 보면 4BEC로 시작하는 값의 맨 끝 8자리를 아래 local.properties 정보의 signing.keyId에 적어줍니다.

이 키에서는 912ABC12이 해당합니다. 이 키는 앞으로 keyserver에 등록할 때, 다운로드할 때, maven 배포할 때 모두 사용하게 됩니다.

signing.keyId=912ABC12
signing.password=GPG 키를 생성할 때 적었던 비밀번호
signing.key=GPG 키를 통해 얻은 BASE64 키 정보
ossrhUsername=지라에 가입한 Username
ossrhPassword=지라에 가입한 Password

keyserver에 등록합니다.

발행한 키를 ubuntu에 등록해 주어야 합니다.

참고로 8자리의 키코드를 입력하지 않고, 전체 키값을 입력했더라도 당황하지 마세요. 똑같이 등록은 되어 있고, 확인하고 싶다면 로컬의 전체 키코드를 –recv-kyes로 해보시면 됩니다.

gpg --keyserver keyserver.ubuntu.com --send-keys 912ABC12

만약 키 정보를 다운로드 또는 갱신하고 싶으시다면 아래 명령어를 활용할 수 있습니다.

gpg --keyserver keyserver.ubuntu.com --recv-keys 912ABC12

key 정보를 얻어보겠습니다.

ubuntu 서버에 등록까지 모두 마쳤습니다. 이제 BASE64로 압축하여 업로드에 사용할 key 정보를 얻어보겠습니다.

gpg --export-secret-keys 912ABC12 | base64

이 키는 매우 길게 나오는데, 여기서는 별도의 파일을 만들지 않고, 그냥 통째로 붙여서 사용합니다. 위에서 작성한 local.properties의 key 부분에 방금 생성한 키 전체를 복사 붙여넣기 합니다.

signing.keyId=912ABC12
signing.password=GPG 키를 생성할 때 적었던 비밀번호
signing.key=lQdGBGHIJjkBEAClnA...PmKOfYhAXlw==
ossrhUsername=지라에 가입한 Username
ossrhPassword=지라에 가입한 Password

여기까지 하면 GPG 키 발행도 끝나고, 배포 준비가 완료되었습니다.

로컬에 있는 키 정보 확인

로컬에 가지고 있는 키 정보를 확인하고 싶다면 아래와 같습니다.

gpg --list-keys

우분투 서버에 send-keys 한 데이터를 날리고 싶다면 아래 2과정을 거쳐주시면 로컬과 리모트 모두에서 제거됩니다.

먼저 secret-keys를 제거합니다.

gpg --keyserver keyserver.ubuntu.com --delete-secret-keys keycode

그리고 keys를 한 번 더 제거합니다.

gpg --keyserver keyserver.ubuntu.com --delete-keys keycode


6. 지라 계정과 GPG 정보를 활용해 스크립트에 계정 정보를 추가로 작성합니다.

6번 과정은 5번 과정에서 모두 확인했지만 한 번 더 정리하면

자신의 로컬 프로젝트의 local.properties를 열어 다음을 등록해 주시면 됩니다.

signing.keyId=912ABC12
signing.password=GPG 키를 생성할 때 적었던 비밀번호
signing.key=lQdGBGHIJjkBEAClnA...PmKOfYhAXlw==
ossrhUsername=지라에 가입한 Username
ossrhPassword=지라에 가입한 Password

당연히 local.properties는 github에 배포되어 있으면 안 됩니다.


7. 배포를 위한 gradlew 명령어를 입력합니다.

드디어 배포 준비가 끝났으니, gradlew 명령어를 이용해 실행해 보겠습니다.

앞에는 내가 배포할 모듈 명 : 뒤에는 명령어입니다. 제 코드를 사용하셨다면 모듈명을 변경하고 publishAllPublicationsToSonatypeRepository을 사용하시면 됩니다.

./gradlew flow-call-adapter-factory:publishAllPublicationsToSonatypeRepository


8. sonatype stagingRepositories에 잘 올라갔는지 확인합니다.

이제 sonatype stagingRepositories에 잘 올라갔는지 확인합니다.

sonatype의 메뉴 중 stagingRepositories를 눌러주시면 됩니다. 잘 배포되었다면 아래 그림과 같이 노출됩니다.

그리고 하단 메뉴 중 Content를 눌러 배포할 파일들이 잘 포함되어 있는지 확인합니다.

image_09


9. sonatype stagingRepositories close and publish을 진행합니다.

이제 배포를 시작해 보겠습니다.

배포는

상단 메뉴 중 Close를 눌러주고, 설명을 추가하고 확인을 눌러줍니다. 하단에 작업 중으로 표시됩니다.

image_10

close 완료되었다면 이제 Release를 진행할 수 있습니다.

image_11

Release을 눌러주고, 설명을 추가하고 이제 기다려주시면 됩니다.


10. Maven Central repository search에서 내 모듈이 잘 배포되었는지 확인합니다.

Release를 눌러주더라도 즉시 배포되는 것이 아니라 몇 시간이 걸리게 됩니다.

image_12

으로 메시지를 남겨두는데 이 메시지가 떴다면 아래 링크의 레파지토리에서는 확인할 수 있습니다.

아래 링크에서 내가 배포한 파일이 잘 배포되었는지 확인할 수 있습니다.

https://repo1.maven.org/maven2/

그리고 몇 시간 더 기다리시면 아래에서도 배포한 groupId 또는 이름으로 검색할 수 있습니다.

Maven Central repository search

image_13


배포한 라이브러리

제가 배포한 라이브러리는 FlowCallAdapterFactory입니다. Retrofit 사용 시 suspend는 바로 가능한데 아직 Flow 형태는 불가능하여 하나 만들고 배포해 보았습니다.

implementation("tech.thdev:flow-call-adapter-factory:1.0.0")

사용법 설명

val retrofit = Retrofit.Builder()
    .baseUrl("https://thdev.tech/")
    .addCallAdapterFactory(FlowCallAdapterFactory()) // 추가
    .build()

suspend 대신 아래와 같이 Flow<>를 활용할 수 있습니다.

interface Service {
    @GET("/example")
    fun getExample(): Flow<Example>

    @GET("/example")
    fun getExample(): Flow<Response<Example>>
}

전체 소스코드는 Retrofit-FlowCallAdapterFactory에서 확인할 수 있습니다.


마무리

JCenter는 별도의 인증 과정이 없어 매우 쉽게 배포할 수 있었는데, maven은 넘나 옛날의 GUI를 가진 사이트도 좀 봐야 하고, GPG 키 발행도 해야 하고 많이 복잡했습니다.

GPG 키 발행은 다행히 stream.io에 친절하게 나와있었고, gradle.kts로 작성한 내용은 위에서 언급한 블로그에 잘 나와있었습니다.

거기에 buildSrc의 precompiled를 사용하면서 삽질한 내용이 대부분이라서 하루 넘게 걸렸네요.

처음이 어렵지 이후에는 쉽다는 말이 이해가 됩니다. 잘 구성해두고 재활용할 수 있으니깐요.

배포한 코드는 제가 작업 중인 레몬트리에(앱은 개발 중) 추후 들어갈 예정입니다.

이 글을 참고하셔서 배포에 성공하시길 바랍니다.



About Taehwan

My name is Taehwan Kwon. I have developed Android for 6 years and blog has been active for eight years.

Comments