KMM: Create a Shared Binary Library for Android and iOS

March 3, 2023
 
Write Your Code Logic Once and Share It With Your Local Native Android and iOS User Interface

In this article we will be building a KMM library that will create a binary library that could be shared with iOS and Android in the form of an XCframework and Android Archive (AAR) respectively.

In my previous article, KMM: Building a Simple Application for Android and iOS, I covered how you could create an all-in-one project, which contains common code that is shared with Android and iOS local native applications within a single project. Please read this article to see how to get KMM setup on your development machine, along with dependencies and installation confirmation.

In this article we will be isolating the shared code into its own project library that can then be used as a binary dependency for external Android and iOS applications.

You can download the code for this article:

git clone https://CodeGorilla@bitbucket.org/CodeGorilla/cg-lib-kmm-shared.git
All of the code we will be building in this article for both Android and iOS will be done within Android Studio. As of this article I am using the following:
  • Android Studio Electric Eel
  • Java 19
  • Gradle 7.6

Create Kotlin Multiplatform Library

Open Android Development Studio and create a new project. Select the Kotlin Multiplatform Library option.


Enter the name of your library and select your save location and Android SDK.


Enter the name of your shared module and select iOS framework distribution: XCFramework.


Troubleshooting

At this point you have a bare bones KMM library. If you have any errors in your build, please refer to my previous article KMM: Building a Simple Application for Android and iOS which fixes some gradle or JDK issues you may encounter.

Testing

Because we are building a library, without a user interface, it is important to run some unit tests. When you build the library with the template it will automatically create a Greeting.kt class in the commonMain folder and a corresponding commonTest.kt class within the commonTest folder.
To run the test, simply open the commonTest.kt file and you should see green "run" buttons to the left of the class and fun statements:
  • If you click the "run" button on the class it will run all of the tests.
  • If you click the "run" button on the fun, it will run only that test.

In this case we only have 1 test so both buttons do the same thing. When you click on the "run" button you can select to run for Android or iOS. They should both pass without any further code updates.

Adding Functionality

Once you have confirmed that the default template code runs successfully, we can now begin to update our library to contain our custom logic.

For this example, we are going to add a new TemperatureConverter class which will contain 2 functions that will simply convert Celsius to Fahrenheit and vice versa.

Right click on commonMain/kotlin/com.code_gorilla.kmmlibrary and select New Kotlin Class/File. Add a new Class named TemperatureConverter.

Enter the following code into your new TemperatureConverter.kt file:

package com.code_gorilla.kmmlibrary

class TemperatureConverter {
fun celsiusToFahrenheit(celsius: Double): Double {
return celsius * 1.8 + 32.0
}

fun fahrenheitToCelsius(fahrenheit: Double): Double {
return (fahrenheit - 32.0) / 1.8
}
}

Adding Unit Test

We are going to add a new TemperatureConverterTest class which will contain 2 tests that will test each of our new functions.

Right click on commonTest/kotlin/com.code_gorilla.kmmlibrary and select New Kotlin Class/File. Add a new Class named TemperatureConverterTest.

Enter the following code into your new TemperatureConverterTest.kt file:

package com.code_gorilla.kmmlibrary

import kotlin.test.Test
import kotlin.test.assertEquals

class TemperatureConverterTest {

@Test
fun celsiusExample() {
val c = TemperatureConverter().fahrenheitToCelsius(fahrenheit = 0.00)
val expectedC: Double = -17.77777777777778
assertEquals(c, expectedC)
}

@Test
fun fahrenheitExample() {
val f = TemperatureConverter().celsiusToFahrenheit(celsius = 0.00)
val expectedF: Double = 32.0
assertEquals(f, expectedF)
}
}

Running the Test

As we did previously with the template test, you should be able to run the 2 tests by clicking on the "run" button to the left of the class and you should see that both of the tests pass.


Build the Library for Android and iOS

At this point, we have written some basic Kotlin functions within a self-contained library and tested that it works. We are now ready to build the library for use within other projects. In this case we will be building the library for both Android and iOS.

Clean Up

Let's start by cleaning our build folders to ensure we are starting with a clean slate by running the gradle clean. Open your terminal/command prompt, navigate to the root folder of your project and execute the following command:

gradle clean

Android

In your terminal/command prompt window, execute the following gradle command:

gradle build

If you get a warning, similar to the following during the build 'compileReleaseUnitTestJavaWithJavac' task (current target is 1.8) and 'compileReleaseUnitTestKotlinAndroid' task (current target is 19) jvm target compatibility should be set to the same Java version., you can fix it by adding the following compileOptions to the android section your build.gradle.kts file:

android {
namespace = "com.code_gorilla.kmmlibrary"
compileSdk = 33
defaultConfig {
minSdk = 27
targetSdk = 33
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_19
targetCompatibility = JavaVersion.VERSION_19
}
}

After you update the build.gradle.kts file, perform and gradle sync and run the build again. The warning should now go away.

When you run the build, you will be creating the Android Archive (AAR) files in the following location: /source/codeGorillaLibrary/build/outputs/aar. The AAR files can now be used as a dependency within other Android applications.

iOS

When you ran the gradle build command above, you created the Android files and you also created the iOS framework files:

  • /source/codeGorillaLibrary/build/bin/iosSimulatorArm64
  • /source/codeGorillaLibrary/build/bin/iosArm64
  • /source/codeGorillaLibrary/build/bin/iosX64

Our objective in this article is to create XCFramework files, not framework files. So we have one additional step to accomplish this goal.

In your terminal/command prompt window, execute the following gradle command:

gradle assembleXCFramework

Upon successful completion, you should now see your XCFramework files in the following location: /source/codeGorillaLibrary/build/XCFrameworks


SUCCESS! We now have our library prepared for both Android and iOS!

References



 
Return to articles