KMM — Publish Android / JVM SDK Binaries

Rakesh Chander
3 min readFeb 12, 2022

KMM has been getting attention of developers and it , obviously, deserves that.

We have different dependency managers for Android / JVM, and KMM binaries are required to be made available on same for easy integration process of KMM Library consumers.

In this article — I am going to explain the steps needed for publishing KMM libraries via

  • Maven Central

I have opted for below formats of SDKs — to be shared

  • AAR — Android
  • JAR — JVM

Lets attempt for Android & JVM SDK publish

First Create a SonaType account — Refer below

SetUp GPG Keys — for Signing of Release SDK Binary

Generate GPG keys
— It will ask you to
— enter password for key — GPG_PRIVATE_PASSWORD
— enter email ID — this will be asked for verification when you upload the public key

brew install gnupggpg --gen-key

Copy “GPG_PUBLIC_KEY” from output of above command

Distributing GPG_PUBLIC_KEY — Export Armor Public Key — $GPGKEY

gpg — output mykey.asc — export -a $GPGKEY

Upload Public Key on — https://keys.openpgp.org
— Verify Email

Get GPG_PRIVATE_KEY from GPG Public Key — $GPGKEY

gpg — armor — export-secret-key $GPGKEY

Add ENV variable in your .bash_profile / .zshrc / .profile / .zprofile

  • GPG_PRIVATE_PASSWORD
  • GPG_PRIVATE_KEY
  • SONATYPE_USERNAME
  • SONATYPE_PASSWORD

Source your profile in terminal OR Android Studio / IntelliJIdea IDE terminal

source ~/.zshrc

Lets move to Project Now — add below to plugin section of build.gradle.kts of module

id("maven-publish")
id("signing")
id("org.jetbrains.dokka")

At global level — declare below variables

group = "<group_id_sonatype_account>"
version = "1.0.0"

Under Kotlin section — add below for Android & JVM SDK outputs for publish

android {
publishLibraryVariants("release")
}
jvm {
compilations
.all {
kotlinOptions
.jvmTarget = "1.8"
}
}

In build.gradle.kts, add below —

val dokkaOutputDir = "$buildDir/dokka"/**
* This task generates documentation
*/

tasks.dokkaHtml {
outputDirectory
.set(file(dokkaOutputDir))
}

/**
* This task deletes older documents
*/
val deleteDokkaOutputDir by tasks.register<Delete>("deleteDokkaOutputDirectory") {
delete(dokkaOutputDir)
}

/**
* This task creates JAVA Docs for Release
*/
val javadocJar = tasks.register<Jar>("javadocJar") {
dependsOn(deleteDokkaOutputDir, tasks.dokkaHtml)
archiveClassifier.set("javadoc")
from(dokkaOutputDir)
}

val sonatypeUsername
: String? = System.getenv("SONATYPE_USERNAME")
val sonatypePassword: String? = System.getenv("SONATYPE_PASSWORD")

/**
* Publishing Task for MavenCentral
*/
publishing
{
repositories {
maven {
name="kotlin"
val
releasesRepoUrl = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
val snapshotsRepoUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
credentials {
username = sonatypeUsername
password = sonatypePassword
}
}
}

publications {
withType<MavenPublication> {
artifact(javadocJar)
pom {
name.set("kotlin")
description.set("<LIBRARY_DESCRIPTION>")
licenses {
license {
name.set("Apache")
url.set("https://opensource.org/licenses/Apache-2.0")
}
}
url.set("<GIT_LIBRARY_URL>")
issueManagement {
system.set("Github")
url.set("<GIT_LIBRARY_ISSUES_URL>")
}
scm {
connection.set("<GIT_LIBRARY_CLONE_PATH>")
url.set("<GIT_LIBRARY_URL>")
}
developers {
developer {
name.set("<NAME>")
email.set("<EMAIL>")
}
}
}
}
}
}

/**
* Signing JAR using GPG Keys
*/
signing
{
useInMemoryPgpKeys(
System.getenv("GPG_PRIVATE_KEY"),
System.getenv("GPG_PRIVATE_PASSWORD")
)
sign(publishing.publications)
}

Sync your gradle file. You will find below tasks added to your Project

  • publish
  • publishToMavenLocal

You can execute these commands now via Terminal OR double click from task list.

Release from MavenCentral account

Login To https://s01.oss.sonatype.org/#stagingRepositories

Under Staging Repositories Section

  • Select module
    — Tap on “Close” — enter remarks and submit
    — Once “Release” — gets enabled — tap on that — enter remarks and submit

Now you can import in your KMM, Android, JVM projects following below —

Android / KMM Projects

Kotlin / KMM

App level build.gradle

repositories {
mavenCentral()
}
dependencies {
implementation '<group_id>:<library_name>:<version>'
}

JAVA

App level build.gradle

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation '<group_id>:<library_name>:<version>'
}

Project level build.gradle

plugins {
id 'org.jetbrains.kotlin.android' version '1.5.30' apply false
}

JVM

JAVA

Add below in build.gradle files -

plugins {
id 'java'
id 'application'
id 'org.jetbrains.kotlin.jvm' version '1.5.31'
}
[compileKotlin, compileTestKotlin].forEach {
it.kotlinOptions {
jvmTarget = '11'
}
}
repositories {
mavenCentral()
}
dependencies {
implementation '<group_id>:<library_name>:<version>'
}

Add below in module-info.java -

requires kotlin.stdlib;
requires <library_name>.jvm;

Kotlin

Add below in build.gradle files -

repositories {
mavenCentral()
}
dependencies {
implementation '<group_id>:<library_name>:<version>'
}

Add below in module-info.java -

requires <library_name>.jvm;

All Set!! Distribute — Import SDKs

--

--

Rakesh Chander

I believe in modular development practices for better reusability, coding practices, robustness & scaling — inline with automation.