Kotlin/Native iOS

2. Creating Simple Framework with Describing Some K/N Features

Yuya Horita
Quick Code
5 min readDec 28, 2018

--

iOS Specific Codes in Kotlin

We configured K/N project previously.

In this chapter, let’s create simple framework with K/N features.

First, create iosMain/kotlin/actual.kt directories and file in the same way as we did here.

This is the scripts. If you configure your Xcode project as this chapter, building in Xcode invokes building this shared module.

Once you build, Xcode has reference to the function defined above.

Hello!!!

Expect & Actual

We sometimes want to separate behaviors on each platform. We can do that using expect and actual keywords.

helloWorld() and helloiOS() are not needed anymore.

Instead, define the following functions.

Here, you don’t have to type import platf....... . When you type NSDate in actual.kt, required packages are automatically complemented by Android Studio. If not, try gradle sync again.

In iosMain part, you used Foundation framework from Kotlin!! Other frameworks can also be used.

Currently, pure swift modules are not supported yet. A swift library whose API is exported to Objective-C with @objc can be used. (2018/12/20)

We used expect and actual . expect is available only in commonMain . The expect specified function’s behavior depends on each platform modules’ actual function.

If you don’t define actual function, this error appears. Safely.

Let’s call showCurrentTime() function.

CommonKt.showCurrentTime()// on Console
2018-12-20 08:43:54 +0000

🎉 🎉

expect and actual can also be used for class. This means expect annotation class is supported. This is important, especially for Android developers.

OptionalExpectation is available in case you don’t have to add annotation for specific platform. Practical example is in Expect Annotation Class section below.

Interoperability.

There is an interoperability between Kotlin and Swift, Objective-C.

Basic with interface vs protocol

Interfaces defined in Kotlin are exported to Swift/Objective-C protocol.

interface Common {
val languageName: String
}

Define this interface in common.kt , then it is available in Swift. Like,

final class SwiftCommon: Common {
let languageName: String = "swift"
}

the Common interface became Common protocol in Swift. Take a look in detail this protocol.

In Xcode, Jump to Definition of it. (command+click shows the menu)

Then, you’ll see.

__attribute__((swift_name("Common")))
@protocol SharedNativeCommon
@required
@property (readonly) NSString *languageName;
@end;

In fact, Kotlin/Native doesn’t interop with Swift directly yet, only via Objective-C at the moment. (2018/12/20)

Swift can refer this Objective-C protocol as Common, thanks to __attribute__ .

Annotation interoperability with @Throws and throws

There are some interop between Kotlin annotation and Swift keyword. One of them is @Throws annotaion and throws keyword.

Be careful, @Throws annotation is an annotation class defined in kotlin-stdlib / kotlin.native . This means you can use it only in actual.kt in native module.

So, define this class in actual.kt .

class Interop {
@Throws
fun sometimesErrorThrown(id: Int): String {
if (id != 0) {
return "OK"
} else {
throw Exception()
}
}
}

We call it in ViewController.swift . The function with @Throws annotation was exported as throws function.

Let’s catch some errors.

The output is the following.

Catching error from @Throws function.

We could catch error 🎉.

Kotlin, Swift, Objective-C mapping from reference

There are many other mapping. You can check them here.

Expect Annotation Class

In the previous section, we defined class Interop in actual.kt .

But, what if you want to use the class in other platforms?

This class uses @Throw annotation and it is available only in native module, not available in Android.

In such a case, expect annotation class is useful.

First, move Interop class definition to common.kt from actual.kt . Unresolved reference error appears in this moment.

To resolve, define expect annotation class and replace @Throws annotation to @NativeThrows .

Next, do typealias the class in actual.kt. Like,

actual typealias NativeThrows = Throws

The NativeThrows annotation class has primary constructor with long argument, vararg val expectionCla.... . This is same type as the argument of native Throws annotation class primary constructor.

Native module’s @Throws annotation definition.

In this section, we modified only Kotlin codes, did nothing to swift codes. But the previous codes work correctly.

One big change is that you are able to use the class from other platform codes, like Android, could share codes 🎉 🎉

We haven’t prepared other modules here, but if you prepare and don’t need any annotation, use OptionalExpectation . In this case,

Then, you don’t have to typeactual typealias …. Build will succeed without it.

Try it. Just comment out.

//actual typealias NativeThrows = Throws

And run Xcode. Some warnings will appear like above, because sometimesErrorThrown function is no longer throws function.

This shows @NativeThrows annotation changed to nothing from @Throws annotation typealias.

Swift cannot catch the error, but throw Exception() is performed in sometimesErrorThrown when argument id == 0. So, it crashes 😱

Be careful.

OptionalExpectation is experimental, so you need additionally @ExperimentalMultiplatform annotation. reference: here

Summary

We developed simple framework by Kotlin. I introduced some features of Kotlin/Native, interoperability, expect & actual keywords and native specific API.

I have other articles. Please check them 🙏 Thank you.

--

--

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