<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ekaterina Petrova</title>
    <description>The latest articles on DEV Community by Ekaterina Petrova (@kathrinpetrova).</description>
    <link>https://dev.to/kathrinpetrova</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F394963%2F73a4c7cf-10ab-462d-8e67-2ed24ba50762.png</url>
      <title>DEV Community: Ekaterina Petrova</title>
      <link>https://dev.to/kathrinpetrova</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kathrinpetrova"/>
    <language>en</language>
    <item>
      <title>Publishing your Kotlin Multiplatform library to Maven Central</title>
      <dc:creator>Ekaterina Petrova</dc:creator>
      <pubDate>Thu, 25 Mar 2021 12:40:40 +0000</pubDate>
      <link>https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-going-public-4a8k</link>
      <guid>https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-going-public-4a8k</guid>
      <description>&lt;p&gt;Now when we've built our first Kotlin Multiplatform library and learned about multiplatform library publishing format nothing can stop us from going public and releasing our library to MavenCentral!&lt;/p&gt;

&lt;h1&gt;
  
  
  Registering a Sonatype account
&lt;/h1&gt;

&lt;p&gt;If this is your first library, or you’ve only ever used Bintray to do this before, you will need to first register a Sonatype account.&lt;/p&gt;

&lt;p&gt;There are many articles describing the registration process on the internet. &lt;a href="https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/#overview" rel="noopener noreferrer"&gt;The one from GetStream&lt;/a&gt; is exhaustive and up to date. You can start by following the first four steps, including "Generating a GPG key pair":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register a Jira account with Sonatype (you can use &lt;a href="https://issues.sonatype.org/browse/OSSRH-65092" rel="noopener noreferrer"&gt;my issue&lt;/a&gt; as an example). ✅&lt;/li&gt;
&lt;li&gt;Verify your ownership of the group ID you want to use to publish your artifact by creating a GitHub repo. ✅&lt;/li&gt;
&lt;li&gt;Generate a GPG key pair for signing your artifacts. ✅&lt;/li&gt;
&lt;li&gt;Publish your public key. ✅&lt;/li&gt;
&lt;li&gt;Export your private key. ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the Maven repository and signing keys for your library are prepared, we are ready to move forward and set up our build to upload the library artifacts to a staging repository and then release them!&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up publication
&lt;/h1&gt;

&lt;p&gt;Now we need to tell Gradle how to publish our libraries. Most of the work is already done by &lt;code&gt;maven-publish&lt;/code&gt; and Kotlin Gradle Plugins – all the required publications are created automatically. We've already seen the result when we published our library to the local Maven repository. But for publishing it to Maven Central we need to take some additional steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure public Maven repository URL and credentials.&lt;/li&gt;
&lt;li&gt;Provide a description and &lt;code&gt;javadocs&lt;/code&gt; for all library components.&lt;/li&gt;
&lt;li&gt;Sign publications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's handle all of these tasks by writing some Gradle scripts! I suggest extracting all the publication-related logic from our library module build.script, so you can easily reuse it for other modules in the future. &lt;/p&gt;

&lt;p&gt;The most idiomatic and flexible way to do that is to use &lt;a href="https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins" rel="noopener noreferrer"&gt;Gradle’s precompiled script plugins&lt;/a&gt;. Our build logic will be provided as a &lt;em&gt;precompiled script plugin&lt;/em&gt; and could be applied by plugin ID to every module of our library. &lt;/p&gt;

&lt;p&gt;To implement this, we need to put our publication logic into a separate Gradle project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add a new gradle project &lt;code&gt;convention-plugins&lt;/code&gt; inside your library root project by creating a new folder named &lt;br&gt;
&lt;code&gt;convention-plugins&lt;/code&gt; with &lt;code&gt;build.gradle.kts&lt;/code&gt; in it. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficig8sxcu3diab1wktin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficig8sxcu3diab1wktin.png" alt="Gradle project structure"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put the following in the &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;`kotlin-dsl`&lt;/span&gt; &lt;span class="c1"&gt;// Is needed to turn our build logic written in Kotlin into Gralde Plugin&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;gradlePluginPortal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// To use 'maven-publish' and 'signing' plugins in our own plugin&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;convention.publication.gradle.kts&lt;/code&gt; file in the &lt;code&gt;convention-plugins/src/main/kotlin&lt;/code&gt; directory. This is where all the publication logic will be stored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put all the required logic there. Applying just &lt;code&gt;maven-publish&lt;/code&gt; is enough for publishing to the local Maven repository, but not to Maven Central. In the provided script we get the credentials from &lt;code&gt;local.properties&lt;/code&gt; or environment variables, do all the required configuration in the ‘publishing’ section, and sign our publications with the signing plugin:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.gradle.api.publish.maven.MavenPublication&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.gradle.api.tasks.bundling.Jar&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.gradle.kotlin.dsl.`maven-publish`&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.gradle.kotlin.dsl.signing&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.*&lt;/span&gt;

&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;`maven-publish`&lt;/span&gt;
   &lt;span class="n"&gt;signing&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Stub secrets to let the project sync and build without the publication values set up&lt;/span&gt;
&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"signing.keyId"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"signing.password"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"signing.secretKeyRingFile"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ossrhUsername"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ossrhPassword"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

&lt;span class="c1"&gt;// Grabbing secrets from local.properties file or from environment variables, which could be used on CI&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;secretPropsFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rootProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"local.properties"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secretPropsFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;secretPropsFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;onEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
       &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"signing.keyId"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SIGNING_KEY_ID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"signing.password"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SIGNING_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"signing.secretKeyRingFile"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SIGNING_SECRET_KEY_RING_FILE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ossrhUsername"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OSSRH_USERNAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ossrhPassword"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OSSRH_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;javadocJar&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registering&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Jar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;archiveClassifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"javadoc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getExtraString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;publishing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Configure maven central repository&lt;/span&gt;
   &lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;maven&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sonatype"&lt;/span&gt;
           &lt;span class="nf"&gt;setUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nf"&gt;credentials&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getExtraString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ossrhUsername"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getExtraString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ossrhPassword"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// Configure all publications&lt;/span&gt;
   &lt;span class="n"&gt;publications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MavenPublication&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

       &lt;span class="c1"&gt;// Stub javadoc.jar artifact&lt;/span&gt;
       &lt;span class="nf"&gt;artifact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;javadocJar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

       &lt;span class="c1"&gt;// Provide artifacts information requited by Maven Central&lt;/span&gt;
       &lt;span class="nf"&gt;pom&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MPP Sample library"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sample Kotlin Multiplatform library (jvm + ios + js) test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://github.com/KaterinaPetrova/mpp-sample-lib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

           &lt;span class="nf"&gt;licenses&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nf"&gt;license&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://opensource.org/licenses/MIT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nf"&gt;developers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nf"&gt;developer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"KaterinaPetrova"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ekaterina Petrova"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ekaterina.petrova@jetbrains.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nf"&gt;scm&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://github.com/KaterinaPetrova/mpp-sample-lib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;

       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Signing artifacts. Signing.* extra properties values will be used&lt;/span&gt;

&lt;span class="nf"&gt;signing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publishing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publications&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back to your library project. Ask Gradle to prebuild your plugins by adding the following in the root &lt;code&gt;settings.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;includeBuild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"convention-plugins"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we can apply this logic in our library &lt;code&gt;build.script&lt;/code&gt;. In the &lt;code&gt;plugins&lt;/code&gt; section, replace using &lt;code&gt;maven-publish&lt;/code&gt; with using our &lt;code&gt;conventional.publication&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"multiplatform"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.4.30"&lt;/span&gt;
   &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"convention.publication"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don’t forget to create a &lt;code&gt;local.properties&lt;/code&gt; file with all the necessary credentials and &lt;strong&gt;make sure you have added it to .gitignore 🗝&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;signing.keyId=...
signing.password=...
signing.secretKeyRingFile=...
ossrhUsername=...
ossrhPassword=...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now take a deep breath, make &lt;code&gt;./gradlew clean&lt;/code&gt; and sync the project. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ku5kppqoqq146zzh3m0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ku5kppqoqq146zzh3m0.png" alt="Maven publication Gradle tasks"&gt;&lt;/a&gt;&lt;br&gt;
New Gradle tasks related to the Sonatype repository should appear in the publishing group – that means that everything is ready for you to publish your library!&lt;/p&gt;
&lt;h1&gt;
  
  
  Publishing your first library to MavenCentral
&lt;/h1&gt;

&lt;p&gt;In the beginning of the article I promised you that you will be able to publish your library in just a one click – and now is the moment of truth! To upload your library to Sonatype Repository just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew publishAllPublicationsToSonatypeRepository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The so-called staging repository will be created, and all the artifacts for all publications will be uploaded to that repository. All that is now needed is to check that all the artifacts you wanted to upload have made it there and to press the “release” button!&lt;/p&gt;

&lt;p&gt;These final steps are well-described in &lt;a href="https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/#your-first-release" rel="noopener noreferrer"&gt;the now-familiar article&lt;/a&gt;. In short, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://s01.oss.sonatype.org/" rel="noopener noreferrer"&gt;https://s01.oss.sonatype.org/&lt;/a&gt; and log in using the credentials you used in Sonatype Jira.&lt;/li&gt;
&lt;li&gt;Find your repository in the ‘Staging repositories’ section.&lt;/li&gt;
&lt;li&gt;Close it.&lt;/li&gt;
&lt;li&gt;🚀 Release it!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go back to the Jira Issue you created and let them know you released your first component to activate the sync to Maven Central. &lt;em&gt;This step is needed only if it’s your first release.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz06v8kxi0io3b45vso83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz06v8kxi0io3b45vso83.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Soon your library will become available at &lt;a href="https://repo1.maven.org/maven2/" rel="noopener noreferrer"&gt;https://repo1.maven.org/maven2/&lt;/a&gt; and other developers will be able to add it as a dependency. And in a couple of hours, it will become &lt;a href="https://search.maven.org/" rel="noopener noreferrer"&gt;discoverable in Maven Central Repository Search&lt;/a&gt;!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jn9h57szxned439ngmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jn9h57szxned439ngmy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Congratulations! 🎉 You’ve just created your first Kotlin Multiplatform Library and published it on Maven Central! &lt;/p&gt;

&lt;p&gt;This is how you can now depend on the published version:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;android&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;ios&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;commonMain&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;getting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.github.katerinapetrova:mpp-sample-lib:1.0.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pretty simple, right? If you check the external dependencies section, you will see that it is quite clever as your project only downloads the artifacts of the platforms you actually target, not all of them every time. Thanks to the Gradle module metadata feature, you only have to specify dependencies on the library once in the shared source set, even if it is used in platform source sets.&lt;/p&gt;

&lt;p&gt;A lot of work has been done, but of course, it’s just the beginning of the journey. The most interesting part is ahead: to support and improve your library continuously, so you can provide your users the best DX and evolve the KMM ecosystem together with other library creators and contributors.&lt;/p&gt;
&lt;h2&gt;
  
  
  Next useful steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Now that you have published your library to Maven Central, it's time to let others know – and what better way than to &lt;a href="https://shields.io/category/version" rel="noopener noreferrer"&gt;add a badge&lt;/a&gt; to your project's README! &lt;/li&gt;
&lt;li&gt;Add your library to &lt;a href="https://libs.kmp.icerock.dev/" rel="noopener noreferrer"&gt;the community-driven list of Kotlin Multiplatform libraries&lt;/a&gt; to increase its discoverability.&lt;/li&gt;
&lt;li&gt;Take a look into the possibility &lt;a href="https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/#automating-sonatype-actions" rel="noopener noreferrer"&gt;to automate the release process&lt;/a&gt; and share your experience with the community, if you’ve already successfully made it this far!&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KaterinaPetrova" rel="noopener noreferrer"&gt;
        KaterinaPetrova
      &lt;/a&gt; / &lt;a href="https://github.com/KaterinaPetrova/mpp-sample-lib" rel="noopener noreferrer"&gt;
        mpp-sample-lib
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sample Kotlin Multiplatform library (jvm + ios + js)
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>kotlin</category>
      <category>multiplatform</category>
    </item>
    <item>
      <title>How a Kotlin Multiplatform library is published?</title>
      <dc:creator>Ekaterina Petrova</dc:creator>
      <pubDate>Thu, 25 Mar 2021 12:40:27 +0000</pubDate>
      <link>https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-discovering-the-library-structure-3oeo</link>
      <guid>https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-discovering-the-library-structure-3oeo</guid>
      <description>&lt;p&gt;In the first part of the series, we've created our first multiplatform library and published it to the local Maven. Before going public, let's discover published artifacts to get an understanding of the multiplatform publishing format.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TL;DR: The Kotlin Gradle plugin creates and configures your library publications automatically, so you don't need to know the details of the publication scheme to successfully deliver your library. But if you are curious, let's discuss it a little!&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Discovering your library structure
&lt;/h1&gt;

&lt;p&gt;If you have published regular platform (for example, android) libraries before, you may notice that the publishing format of a multiplatform library differs quite a lot. There are multiple artifacts for one version of your library, their content format is different (.jar vs .klib),  and the number of source sets doesn’t match the number of result artifacts.&lt;/p&gt;

&lt;p&gt;This is because ordinary publishing is not enough for a multiplatform library. Multiplatform libraries have more complex structures compared to normal ones, so the publication is less trivial as well. Here are key differences to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiplatform libraries consist of multiple parts: common parts with &lt;code&gt;expect&lt;/code&gt;s declarations and platform-specific parts with actual implementations.&lt;/li&gt;
&lt;li&gt;Platform-specific code may still be shared across similar platforms (e.g. in a source set shared between the iOS device and simulator, or shared code for all desktop platforms).&lt;/li&gt;
&lt;li&gt;There should be the ability to publish all those parts from a multiple host because of Kotlin/Native cross-compilation limitations. For example, the artifacts for iOS or macOS can be built only on Mac-OS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering all that complexity, adding the ordinary multiplatform dependency requires just a single line of code in your the &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.github.katerinapetrova:mpp-sample-lib:1.0.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how does this magic work? Maven doesn’t operate with targets, source sets, and compilations. It operates only with projects. A project is everything we build and could depend on. Each project is defined by groupId, artifactId, and version, and these three fields are used by Maven as a coordinate system. This is exactly what you are using when copy-pasting a dependency string to your build.gradle file. These coordinates are defined in a .pom file — an XML representation of a Maven project. Let’s take a look at what we have in the local Maven folder of the library we’ve just published:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47n7dhcounnxzui73hk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47n7dhcounnxzui73hk6.png" alt="Multiplatform library in the local Maven folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We published only one library, but there are multiple folders. Each folder represents a separate maven project, containing different artifacts and a .pom file, which describes the project (we can also call them “artifacts”, as the name of the project is stored in the POM &lt;code&gt;artifactId&lt;/code&gt; field).&lt;/p&gt;

&lt;p&gt;So the Kotlin Gradle plugin has created publications, which were used by the &lt;code&gt;maven-publish&lt;/code&gt; plugin to map the sources of our Kotlin Multiplatform library to the Maven artifacts, on which we later could depend on in the consumer project as Gradle modules. This is how it was done:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faurtqhgjghqco6x12mvk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faurtqhgjghqco6x12mvk.png" alt="Kotlin Multiplatform Library Maven representation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s figure out the main points of this transformation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a separate publication for each target. The binary format depends on the target compiler backend:

&lt;ul&gt;
&lt;li&gt;.jar with class files for Kotlin/JVM&lt;/li&gt;
&lt;li&gt;.jar with .js or .klib &lt;a href="https://kotlinlang.org/docs/js-ir-compiler.html" rel="noopener noreferrer"&gt;when using IR Compiler for Kotlin/JS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;.klib for Kotlin/Native&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There is also an additional root publication that stands for the whole library. It consists of two important parts:

&lt;ul&gt;
&lt;li&gt;Kotlin representation of common sources of your library. Kotlin toolchain will use it to provide exact and granular dependencies from your common code to a library's common code.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html" rel="noopener noreferrer"&gt;Gradle Module Metadata&lt;/a&gt;, which tells Gradle where to find other platform-specific parts of a library when you depend on the root artifact in the common source set. This is what allows you to write single-line dependency on a library in a common source set&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kotlinlang.org/docs/mpp-share-on-platforms.html#share-code-in-libraries" rel="noopener noreferrer"&gt;With the hierarchical project structure enabled&lt;/a&gt;, the API of the library’s intermediate source sets is embedded into the library artifacts (common or platform, depending on which targets this set is divided between). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transformation doesn’t look trivial and the described points are just the tip of the iceberg, but the good news is that all the work is done by the Kotlin Gradle plugin. It creates and configures all the relevant publications automatically, so you don't need to create them manually. That significantly reduces the chance of making a mistake, especially for popular configurations. 🎉&lt;/p&gt;

&lt;p&gt;If you want to dive into the details of publication format, I suggest you watch an exciting talk by Dima Savinov, Kotlin Multiplatform team lead. &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5QPPZV04-50"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And now let’s go back to our main goal — &lt;strong&gt;making our library available to the world&lt;/strong&gt;! Check out the last part of the series, which will guide you through the MavenCentral publication process 👀&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>multiplatform</category>
    </item>
    <item>
      <title>Creating your first Kotlin Multiplatform library</title>
      <dc:creator>Ekaterina Petrova</dc:creator>
      <pubDate>Thu, 25 Mar 2021 12:40:04 +0000</pubDate>
      <link>https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-creating-your-first-library-1bp8</link>
      <guid>https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-creating-your-first-library-1bp8</guid>
      <description>&lt;p&gt;Kotlin multiplatform technology &lt;a href="https://blog.jetbrains.com/kotlin/2021/01/results-of-the-first-kotlin-multiplatform-survey/" rel="noopener noreferrer"&gt;is becoming more and more popular&lt;/a&gt; and the ecosystem is changing rapidly. Have you ever wondered about creating a multiplatform library? Now is a great time to start creating one, as there are a lot of open needs in the community and your involvement will be highly appreciated! &lt;/p&gt;

&lt;p&gt;Of course, writing good code and providing useful API should be your top priority as a library author. But if you are publishing your library for the first time, there are some obstacles you’ll need to overcome. For example, &lt;a href="https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/" rel="noopener noreferrer"&gt;as Bintray is shutting down in May 2021&lt;/a&gt;, you have to handle the Maven Central registration process and configure your library for publishing there.&lt;br&gt;
This post will help you through the multiplatform library publishing routine giving you one less thing to worry about so that you can concentrate on the library itself 🧘🏼‍♀️&lt;/p&gt;
&lt;h1&gt;
  
  
  Plan
&lt;/h1&gt;

&lt;p&gt;In the first part of the series we are going to create a multiplatform library that uses platform APIs with expect/actual mechanism, provides a simple API to the users, and supports three targets: &lt;strong&gt;Native&lt;/strong&gt; (iOS or your host machine target, depending on your choice), &lt;strong&gt;JVM&lt;/strong&gt;, and &lt;strong&gt;JavaScript&lt;/strong&gt;. Such a library can be used in any KMM (&lt;a href="https://kotlinlang.org/lp/mobile/" rel="noopener noreferrer"&gt;Kotlin Multiplatform Mobile&lt;/a&gt;) or other &lt;a href="https://kotlinlang.org/docs/mpp-intro.html" rel="noopener noreferrer"&gt;Kotlin Multiplatform&lt;/a&gt; projects. &lt;/p&gt;

&lt;p&gt;If you already have a project you want to publish, you can jump directly to the final step of this part – publishing the library to the local Maven repository to make sure that everything works correctly. In the next part, we will also discover published artifacts to get an understanding of the multiplatform publishing format. Finally, in the last part of the series, we will register a Sonatype account that is needed to publish your library to MavenCentral. &lt;/p&gt;

&lt;p&gt;🤔 &lt;em&gt;If you are feeling a little confused with all the new Maven terminology we are throwing around – it's okay!  Here’s a useful twitter tip, which might help!&lt;/em&gt; &lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1357436828861759491-933" src="https://platform.twitter.com/embed/Tweet.html?id=1357436828861759491"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1357436828861759491-933');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1357436828861759491&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Next, we will set up the mechanism for publishing your project so you'll be able to configure, sign, and publish a library by calling a single Gradle task. Finally, we will publish your library in MavenCentral so that it will become available to developers all over the world!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is lots to do, so let's get started!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ℹ️ Disclaimer: This tutorial is based on official documentation and other existing articles. They all provide useful and up-to-date instructions, but they don't fully cover the bumpy, winding road that is the publishing process. Here you will find a combination of the most relevant existing content and additional information, which should answer all your questions.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up the environment
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;If you want your library to support iOS or macOS targets, you need a macOS to build the native artifacts. But otherwise, you can build your library on any operating system.&lt;/li&gt;
&lt;li&gt;I will be demonstrating using IntelliJ IDEA (&lt;a href="https://www.jetbrains.com/idea/download/" rel="noopener noreferrer"&gt;download the latest version here&lt;/a&gt;) with &lt;a href="https://kotlinlang.org/docs/releases.html" rel="noopener noreferrer"&gt;the latest Kotlin plugin&lt;/a&gt;, but you can use &lt;a href="https://developer.android.com/studio" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt; as well. IntelliJ IDEA comes with a few useful Kotlin wizards, including a multiplatform library wizard. &lt;/li&gt;
&lt;li&gt;For creating the GPG keys that are needed to sign your library, we will use the GPG command-line tool. &lt;a href="https://gnupg.org/download/" rel="noopener noreferrer"&gt;Download&lt;/a&gt; and install it manually, or with package management utilities, for example, brew: &lt;code&gt;brew install gpg&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alright, that’s enough introduction and preparing — let’s start!&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating a multiplatform library
&lt;/h1&gt;

&lt;p&gt;To publish something, we first need to build something! If you don't have a library yet, but you want to get some hands-on experience publishing one, let’s start by creating a sample library &lt;a href="https://kotlinlang.org/docs/multiplatform-library.html#publishing-library-to-maven." rel="noopener noreferrer"&gt;following the official tutorial&lt;/a&gt;, which describes the process of developing a multiplatform library from scratch. &lt;br&gt;
In this tutorial, you will learn how to create a multiplatform library for JVM, JS, and Native platforms, write common tests for all the platforms, and publish the library to a local Maven repository. This library will convert raw data – strings and byte arrays – to Base64 format. To implement the conversion to the Base64 format on the different platforms, you will use the platform capabilities for JVM and JS, and write your own implementation for Native.&lt;/p&gt;
&lt;h2&gt;
  
  
  Supporting iOS target
&lt;/h2&gt;

&lt;p&gt;This tutorial demonstrates building a library that supports native target equals your host target (so if you develop on macOS, then the resulting native artifact will be suitable for running on macOS). However, you can easily configure the supported targets set. For example, you can add the iOS target to make your library suitable for KMM projects. There are two ways to do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you don’t need to support your host target and need only iOS, you could replace the host-dependent native target declaration that was generated by the project wizard with the &lt;code&gt;ios()&lt;/code&gt; target declaration:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;jvm&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// …&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// …&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;hostOs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"os.name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isMingwX64&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hostOs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Windows"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;nativeTarget&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;hostOs&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Mac OS X"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;macosX64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"native"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;hostOs&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Linux"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;linuxX64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"native"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;isMingwX64&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;mingwX64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"native"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;GradleException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Host OS is not supported in Kotlin/Native."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;jvm&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// …&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// …&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;ios&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Don’t forget to also rename source set declarations and folder names according to the target name (&lt;code&gt;nativeMain&lt;/code&gt; -&amp;gt; &lt;code&gt;iosMain&lt;/code&gt; in our case).&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;If you want to support both your host and iOS native targets and share code between them, you should manually &lt;a href="https://kotlinlang.org/docs/mpp-share-on-platforms.html#configure-the-hierarchical-structure-manually" rel="noopener noreferrer"&gt;configure the hierarchical project structure&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Supporting Android target
&lt;/h2&gt;

&lt;p&gt;This tutorial uses &lt;code&gt;jvm()&lt;/code&gt; target declaration for JVM platforms support. The resulting artifact could be used in multiplatform projects that target any JVM platforms, including Android. If you want to make it possible to use your library directly from the Android project, or you need to use Android SDK to implement platform-specific features (for example, working with files stored on the device), use the &lt;code&gt;android()&lt;/code&gt; target declaration instead. To make it work, you need to connect the &lt;code&gt;android-library&lt;/code&gt; Gradle plugin and provide Android-specific information in the &lt;code&gt;android&lt;/code&gt; configuration block in the &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;android&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;compileSdkVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;compileSdkVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
 &lt;span class="n"&gt;sourceSets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;srcFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/androidMain/AndroidManifest.xml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Create AndroidManifest.xml and provide path to it&lt;/span&gt;
    &lt;span class="nf"&gt;defaultConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;minSdkVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;minSDKVersiom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;targetSdkVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;targetSDKVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Additionally, you need to specify the variant names in the Android target, as no artifacts of an Android library are published by default (&lt;a href="https://kotlinlang.org/docs/mpp-publish-lib.html#publish-an-android-library" rel="noopener noreferrer"&gt;see official docs for the details&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;android&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;publishLibraryVariants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Complete &lt;a href="https://kotlinlang.org/docs/multiplatform-library.html#publishing-library-to-maven" rel="noopener noreferrer"&gt;the Create and publish a multiplatform library tutorial&lt;/a&gt; and configure the targets according to your needs. Here is the source code of the sample Base64 library with JVM, JS, and iOS support:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KaterinaPetrova" rel="noopener noreferrer"&gt;
        KaterinaPetrova
      &lt;/a&gt; / &lt;a href="https://github.com/KaterinaPetrova/mpp-sample-lib" rel="noopener noreferrer"&gt;
        mpp-sample-lib
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sample Kotlin Multiplatform library (jvm + ios + js)
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now we push on to the next stage and publish our library! &lt;/p&gt;

&lt;h1&gt;
  
  
  Publishing your library to the local Maven repository &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;The only difference from developing a regular multiplatform module is using &lt;a href="https://docs.gradle.org/current/userguide/publishing_maven.html" rel="noopener noreferrer"&gt;the maven-publish Gradle plugin&lt;/a&gt;. When used with &lt;code&gt;maven-publish&lt;/code&gt;, the Kotlin plugin automatically creates publications for each target that can be built on the current host (&lt;a href="https://kotlinlang.org/docs/mpp-publish-lib.html#structure-of-publications" rel="noopener noreferrer"&gt;doc&lt;/a&gt;). Using the corresponding Gradle tasks provided by the &lt;code&gt;maven-publish&lt;/code&gt; plugin, you can deploy these publications to a remote or local repository.&lt;/p&gt;

&lt;p&gt;If you already have a code you want to publish, then all you need is to apply &lt;code&gt;maven-publish&lt;/code&gt; and provide the library group and version information (&lt;a href="https://kotlinlang.org/docs/multiplatform-library.html#publish-your-library-to-the-local-maven-repository" rel="noopener noreferrer"&gt;see the last step of the tutorial&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"multiplatform"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.4.31"&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"maven-publish"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.jetbrains.base64"&lt;/span&gt;
&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;./gradlew publishToMavenLocal&lt;/code&gt; will upload all the needed artifacts to the local Maven repository, which is a directory on the local machine. You can check the result in this directory, which is usually located in &lt;code&gt;/Users/&amp;lt;user_name&amp;gt;/.m2&lt;/code&gt; directory, or by connecting your library to the sample multiplatform project, for example, the KMM project, which could be easily created with &lt;a href="https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile" rel="noopener noreferrer"&gt;the KMM plugin for Android Studio&lt;/a&gt; project wizard. Add a dependency on your locally published library in the shared module &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;mavenLocal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;android&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;ios&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;commonMain&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;getting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.github.katerinapetrova:mpp-sample-lib:1.0.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best way to explore our new library structure is through the &lt;code&gt;dependency&lt;/code&gt; section in the project tree:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwethjib32vhxofdfyc2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwethjib32vhxofdfyc2c.png" alt="Multiplatform library structure" width="800" height="765"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wow! 😱 There is a lot of stuff in here and I know you must be curious about it! So before going public, let's spend a little time looking at how our library is structured — check out the next part of the series 👀&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>multiplatform</category>
    </item>
  </channel>
</rss>
