Kotlin/Native iOS

1. Configuring K/N Project on Android Studio with Gradle

Yuya Horita
Quick Code
7 min readDec 28, 2018

--

Latest Update 🎉

  • 1st, Mar, 2019
  • Kotlin 1.3.21
  • Gradle 5.1.1
  • Android Studio 3.3

Project Configuration

First, start with configuring K/N project on Android Studio, ver 3.3 .

Click Start a new Android Studio project, select Empty Acticity .

Next, input

  • Application name, here KotlinNativeiOS
  • Package name
  • Save location
  • Language Kotlin
  • Minimum API level, here API 28, but anything is ok.

Finished with the above setting.

The KotlinNativeiOS project will be opened automatically and gradle sync is performed. After that, you’ll see like the above image on left bar.

To setup directory, switch this Android tab to Project tab.

There are some directories and files. Like,

  • .gradle/
  • .idea/
  • app/
  • gradle/
  • build.gradle
  • etc..

Let’s take a look some files.

In build.gradle, ext.kotlin_version = '1.3.20' is written in buildscript . This shows we are using Kotlin version 1.3.20 apparently. Now, Kotlin version 1.3.21 is available. We use it, so replace the variable if needed.

In gradle/wrapper/gradle-wrapper.properties , distributionUrl is defined. In my case, gradle-4.10-1-all.zip are set. I changed to the following.

Then, Sync Now button appears on top. Tap it and gradle sync will start.

Creating the Shared Module

This section’s goal is to create an iOS framework from Kotlin codes.

Right click on KotlinNativeiOS directory. And select New -> Directory.

Input sharedNative (or any name you like). This directory will become shared module.

In the same way, create sharedNative/src/commonMain/kotlin directories.

And create common.kt file in kotlin directory. We define helloWorld function here as below.

package org.kotlin.mpp.mobilefun helloWorld() {
println("Hello World!")
}

We want to call this function from Swift. Let’s update the Gradle scripts.

First, we need to add the new project into the settings.gradle , simply adding the following line to the end.

include ':sharedNative'

Next, create the sharedNative/build.gradle .

After that, write the following codes.

apply plugin: 'kotlin-multiplatform'buildscript {
ext.ios_framework_name = 'KotlinShared'
}
kotlin {
targets {
fromPreset(presets.iosX64, 'ios') {
binaries {
framework("$ios_framework_name") {
embedBitcode('disable')
}
}
}
}
sourceSets {
commonMain.dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
}
}
}

This is a gradle script for using kotlin multiplatform. The presets is iosX64 , for ios simulator, here. If you want to build for ios device, change this presets to iosArm64 . Defining the following variable may be helpful.

final def iosTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
? presets.iosArm64 : presets.iosX64

But, it’s ok. Go forward with presets.iosX64. You need Sync Now here.

We will create the framework.

Open terminal and move to KotlinNativeiOS root directory, or use Android Studio’s Terminal.

We are here. Next, run the following command.

./gradlew :sharedNative:build

gradlew command can run :Module ‘s :task . The above will perform building sharedNative module.

We found debug and release directories in sharedNative/build/bin/ios directory. Each has .framework in it. Frameworks are created 🎉.

ext.ios_framework_name = 'KotlinShared'

We defined an above variable in build.gradle and set it to framework("$ios_framework_name") . The default name is main.framework without it.

You see .dSYM in same directory. Crashlytics or other services uses this debug symbol file to symbolicate crash logs. But it appears only for debug. For release, this issue is reported.

There is one more block you need. This is the task to pack a framework to Xcode. It’s not good for your Xcode project to directly refer to the framework in above debug or release directory because it has build configuration DEBUG or RELEASE . The framework reference should be changed depending on it.

The following task is for that. Define this task in sharedNative/build.gradle .

In the same way, Sync Now and run this task.

Or, click this button for Gradle Sync .

./gradlew :sharedNative:packForXcode

This command performs the sharedNative module’s packForXcode task defined above.

Finally, xcode-frameworks directory and the framework appears. Xcode will refer this framework. Kotlin tutorials are a great way to learn more about Kotlin for Android beginners.

Hello World in Xcode

In this section, we call sharedNative framework’s helloWorld() function. But, it’s not so difficult. Simply, it is just a function of framework. It does not matter whether it is generated from Kotlin here.

So, I’d like to introduce some tips.

  • relative path is good for xcode-frameworks from Xcode project.
  • packForXcode before Compile Sources in build phase.

relative path

First, create KotlinNativeiOS/ios directory and Xcode project with this configuration in it.

  • Single View Application
  • Product Name: SampleiOS
  • Language: Swift

Like above, .xcodeproj path is relative to sharedNative directory (framework in it). The path is $SRCROOT/../../sharedNative . Using relative path, we can configure Xcode settings with environment variables.

K/N generates dynamic framework, so embed it to binaries.

Move to Xcode project’s Generaltab. In Embedded Binaries section, tap + and click Add Other... .

Choose the framework in xcode-frameworks directory.

Create references.

Finished embedding.

Now we need to add this path to Framework Search Path . Here, I use xcconfig file. Right click on SampleiOS group and choose Configuration Settings File

Config.xcconfig was created. Set the path.

FRAMEWORK_SEARCH_PATHS = $(inherited) $SRCROOT/../../sharedNative/build/xcode-frameworks

Tell your project which configuration file is used. If you have already set framework search path directly in Build Settings, replacing it to $(inherited) will reflect the xcconfig file’s setting.

Now we can use sharedNative framework. In ViewController.swift,

🎉 🎉 🎉

packForXcode before Compile Sources in build phase

As I mentioned above, packForXcode is the gradle task to exchange the framework to the one built in proper configuration, DEBUG or RELEASE .

It should be run before compiling sources.

In Build Phases, add new run script phase. It is generated as Run Script. I renamed it to Kotlin/Native. The script is the following.

cd $SRCROOT/../../sharedNative/build/xcode-frameworks./gradlew :sharedNative:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}

Move the phase previous to the Compile Sources phase by dragging.

Kotlin/Native Run Script Phase

Check you can build successfully.

Summary

I explained how to configure Kotlin/Native project, setting up by Android Studio, building by Gradle, using framework in Xcode.

Now, you can convert Kotlin codes to Swift (strictly Objective-C). So try anything what you want to do, like using coroutines.

I have other articles mainly focused on practically using.

--

--

Yuya Horita
Quick Code

Master of Nuclear Physics, CyberAgent, Inc. FRESH LIVE. M3. Software Engineer. Twitter: https://twitter.com/horita_yuya ,GitHub: https://github.com/horita-yuya