Kotlin/Native iOS
2. Creating Simple Framework with Describing Some K/N Features
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
andactual
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 inactual.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.
We could catch error 🎉.
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.
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.
- Coroutines and Immutability of K/N.
- Sample with K/N + Reactive Programming + Architectures. (coming soon)