Creating an iOS framework with… Kotlin

🇫🇷 Parlez-vous Français ? You can read a French Version of this post on our blog at Xebia France.
Kotlin/Native is a new Kotlin dialect which supports compiling code in an executable form that can be run on the targeted system, without needing for a JVM. The Kotlin/Native compiler, named Konan, interfaces with the LLVM compiler infrastructure in order to support a number of targets, such as Linux, macOS, iOS, Web Assembly and others.
First announced in April, Kotlin/Native has now reached v0.6, published in February 2018. Since its version 0.5 Kotlin/Native introduces a new target, which can particularly be useful for iOS projects, that is iOS frameworks.
In this article, we’ll see how to create an iOS framework using Kotlin code. Our library will actually do nothing too fancy, but it’ll be a great starting point for future evolutions.
Please note that to complete this tutorial you will need a machine running macOS and Xcode 9.2.

How Konan works

As mentioned above, Konan interfaces with the LLVM backend compiler in order to support a number of targets, such as Linux, macOS, iOS, Web Assembly and others. The LLVM compiler takes as input an intermediate representation (IR, or LLVM-IR) and generates machine code (or, better, object code) for a number of supported CPU architectures (such as ARM, x86 and many others).
In other words, Konan will compile Kotlin code to LLVM-IR and LLVM will take care of the rest, by compiling LLVM-IR down to ARM (or other CPUs).
Kotlin and LLVM

Before we start: Gradle

In order to complete this tutorial, you’ll need to install Gradle first. If you’ve never stumbled on it, Gradle is the main build tool in the JVM environment and it is used by the vast majority of Android projects. With Gradle, we’ll be able to define dependencies, and define tasks that will take care of compiling our project. Also, and foremost, gradle is easily extendable via plugins, and we’ll actually use one of them to help us creating the tasks we need to create our framework.
The easiest way to install Gradle is via Homebrew:

Project Setup

We then create a new project folder, for instance “MyProject”.
We can now open the shell inside “MyProject” and run

This operation will create the basic configuration for our project.

Now, we’ll need to add the following resources to “MyProject”:
  • An empty gradle.properties file
  • A folder, named “myframework”, which will contain code and properties for our library
  • Inside the “myframework” folder, we’ll be adding:
    • A tree of folders as follows: src/main/kotlin/fr/xebia/myframework
    • Another empty build.gradle file
The result should now be as follows:

This structure follows the conventions of most Java and Kotlin projects and allows us to prepare our project to host other subprojects in the future in case we need it (and we sure will in a further post).

Configuring the environment

Now we’ll be setting the basic properties of our environment.
The settings.gradle file should reference reference the modules of the project we’re building. In our case, it’s “myframework”, so we’ll add to the file the following line:

The root build.gradle file will contain the main configuration used throughout our project and subproject. In particular, we’ll set the kotlin_version to be used (1.2.21) and the version of the compiler (0.6). We also set which repositories will be used by our build script, i.e. jCenter.

Configuring the “myframework” subproject

Let’s open the build.gradle contained in the “myframework” subproject. This file instructs Konan on what and how it will need to handle the compilation.
In particular, via the apply plugin directive, we’ll define the plugin to be used in our context: ‘konan’, which is of course, the plugin used for easily interfacing with the Kotlin/Native compiler.
Also, we’ll instruct our script about its repository: i.e., maven, and its dependency, the kotlin-native-gradle-plugin.

Finally, we’ll add to the same build.gradle file the directives for creating the iOS framework. We’ll be targeting iPhone and the iPhone Simulator, which are based on two different architectures, namely ARM for the iPhone and x86 for the Simulator. We’re also setting, in the framework parameters, the output file name of our task: ‘MyKotlinFramework’.

Here, we’ll also indicate which folder contains our source code, in our case src/main/kotlin.
Not much else to see here, apart from enabling the debugging mode, via the enableDebug true line.

Adding some source code

Now it’s finally the time to add some Kotlin code.

As you clearly understand, this code doesn’t do much, but it’s enough to try out the basic functionalities of Kotlin/Native.

Compiling

That’s pretty much all. We just need to compile our project by running grade.
Before doing this, let’s just run

This should output a number of tasks preconfigured by Gradle. Among them, the compileKonan task, compileKonanMyKotlinFrameworkIphone, compileKonanMyKotlinFrameworkIphone_sim are automatically created by the konan plugin applied in the build.gradle file: as the names say, they will compile code and produce frameworks for iPhone and iPhone simulator.

We can now run

and wait for the project to compile. Please note that Gradle will also take care of automatically downloading the Kotlin/Native compiler for us – even though this’ll take a while.

When the compilation is finished (it may take a little while at the time of writing), verify the contents of the folder myframework/build/konan/bin/iphone_sim: they should contain three files:
  • MyKotlinFramework.framework
  • MyKotlinFramework.framework.dSYM
  • MyKotlinFramework.kt.bc
What are those three files?
The first one is, of course the framework we’ve just produced. The second file, having the dSYM extension, contains the information needed to debug our framework with an lldb debugger, such as the one provided by Xcode. Last, the .kt.bc file is the bitcode file of our program. In other words, it is the binary form of the LLVM Intermediate Representation of our code.

Integrating in an iOS application

In order to try how the framework runs in our iOS app, let’s add it to the “Embedded Binaries” section of our target.
Embedded Binaries Section
Then, in our Swift code, we’ll just need to import the library and use the bar() method of our Foo class. As you’ll see, please note that Konan prefixes all your classes with the trigram of your framework output name. In our case, MyKotlinFramework. In our case, the Foo class will become visible in Objective-C and Swift as MKFFoo.

The complete code of this tutorial is available at this GitHub repo.

Where to go from here?

Needless to say, this is just the beginning. Thanks to Kotlin/Native 0.6 it is now easy to share code between iOS and Android, by using the Multiplatform DSL. This will allow for a more effective reuse of your business logic between your mobile apps, no matter the platform.

Credits

Huge thanks to my colleagues at Xebia France for reviewing this article, in particular Sergio Dos Santos, Benjamin Lacroix, Michaël Ohayon and Julien Datour.