Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Shared Cross-Platform Modules with Kotlin/Native

Shared Cross-Platform Modules with Kotlin/Native

Simone Civetta

February 15, 2018
Tweet

More Decks by Simone Civetta

Other Decks in Programming

Transcript

  1. You

  2. Main platforms: • Xamarin • PhoneGap / Cordova • AppCelerator

    Titanium • React Native • RubyMotion • Flash • ...
  3. JVM

  4. Optionals var a: String = "abc" a = null //

    compilation error Smart casting fun demo(x: Any) { if (x is String) { print(x.length) // x is automatically cast to String } }
  5. Function extensions fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp

    = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp } val l = mutableListOf(1, 2, 3) l.swap(0, 2)
  6. Lambda & Inlines max(strings, { a, b -> a.length <

    b.length }) Data classes data class User(val name: String, val age: Int)
  7. YES

  8. Why Does it Make Sense? 1. Plug into existing codebases

    2. Xcode is still the most suitable IDE for iOS 3. Code for views cannot be shared anyway 4. Either way, you have to master UIKit
  9. My Goal Create viewer apps, sharing parsing logic: • iOS

    (view logic in Swift) • Android (view logic in Kotlin) • Shared parsing library: • iOS ➡ .framework (Kotlin/Native) • Android ➡ .aar (Kotlin/JVM)
  10. Project Setup !"" android/ !"" ios/ #"" common/ !"" build.gradle

    !"" gradle/ #"" slideparser/ !"" build.gradle #"" src/
  11. common/slideparser/build.gradle !"" android/ !"" ios/ #"" common/ !"" build.gradle !""

    gradle/ #"" slideparser/ !"" build.gradle ⬅⬅⬅ #"" src/
  12. common/slideparser/build.gradle (1/3) buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }

    repositories { mavenCentral() } apply plugin: 'konan' apply plugin: 'com.android.library' apply plugin: 'kotlin-android' // ...
  13. common/slideparser/build.gradle (2/3) Android android { compileSdkVersion 26 defaultConfig { //

    ... } sourceSets { main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/test/kotlin' } }
  14. Tasks ./gradlew tasks assemble - Assembles all variants of all

    applications and packages. build - Assembles and tests this project. compileKonanKotlinSlideParserIphone - Build the Kotlin/Native framework \ 'compileKonanKotlinSlideParserIphone' for target 'IPHONE' compileKonanKotlinSlideParserIphone_sim - Build the Kotlin/Native framework 'compileKonanKotlinSlideParserIphone_sim' for target 'IPHONE_SIM'
  15. Multiplatform3 • A new project structure (Kotlin 1.2) • Allows

    to compile the same code to multiple targets: • JVM • JS • Native • Powerful DSL to define dependencies Coming in Kotlin/Native 0.6 3 https://kotlinlang.org/docs/reference/multiplatform.html
  16. IDE

  17. Testing • Unit tests supported in Kotlin/Native • But you

    can use JUnit (or Spek) too • Optimal IDE support
  18. Objective-C Generated Headers !"" KotlinSlideParser.framework #"" Headers $ !"" KotlinSlideParser.h

    ⬅⬅⬅ #"" Info.plist #"" KotlinSlideParser !"" Modules !"" module.modulemap
  19. #import <Foundation/Foundation.h> @class KSPSupport, KSPMyEnum, KSPStdlibEnum, KSPOtherEnum, KSPSlideEntity, KSPSlideEntityPage, KSPMarkdownEntity,

    KSPMarkdownEntityItalic, KSPMarkdownEntityBold; @class KSPMarkdownEntityHeader, KSPMarkdownEntityInlineCode, KSPMarkdownEntityCodeBlock, KSPMarkdownEntityLinks; @class KSPMarkdownEntityPlain, KSPMarkdownEntityRefer, KSPMarkdownEntityDelete, KSPSlideParser; @protocol KSPStdlibComparable; NS_ASSUME_NONNULL_BEGIN @interface KotlinBase : NSObject -(instancetype) init __attribute__((unavailable)); +(instancetype) new __attribute__((unavailable)); +(void)initialize __attribute__((objc_requires_super)); @end; @interface KotlinBase (KotlinBaseCopying) <NSCopying> @end; __attribute__((objc_runtime_name("KotlinMutableSet"))) @interface KSPMutableSet<ObjectType> : NSMutableSet<ObjectType> @end; __attribute__((objc_runtime_name("KotlinMutableDictionary"))) @interface KSPMutableDictionary<KeyType, ObjectType> : NSMutableDictionary<KeyType, ObjectType> @end; __attribute__((objc_subclassing_restricted)) @interface KSPSupport : KotlinBase -(instancetype)init NS_SWIFT_NAME(init()) NS_DESIGNATED_INITIALIZER; -(NSNumber* _Nullable)optionalInt NS_SWIFT_NAME(optionalInt()); -(void)somethingThatThrows NS_SWIFT_NAME(somethingThatThrows()); @end; @protocol KSPStdlibComparable @required -(int32_t)compareToOther:(id _Nullable)other NS_SWIFT_NAME(compareTo(other:)); @end; NS_ASSUME_NONNULL_END
  20. Kotlin / ObjC / Swift Type Mapping Kotlin Objective-C Swift

    Boolean BOOL Bool Float / Double float / double Float / Double Int int32_t Int32 String NSString * String Array<String> StdlibArray * StdlibArray List<String> 2 NSArray<NSString *> * [String] Int? Nullable NSNumber * NSNumber? 2 From 0.6
  21. Kotlin Objective-C Swift interface protocol protocol class class class data

    class class class enum class StdlibEnum StdlibEnum Kotlin Objective-C Swift open (subclassable) open public (subclassable) open
  22. Debugging • Debugging is supported • Compiler produces a .dSYM

    file • "official" LLVM symbolication file for debugging • DWARF format • Allows using Xcode for debugging
  23. Memory Management • ARC-based... • ...with an automatic cycle collector

    on top • Garbage Collection is performed periodically • No weak / unowned references
  24. Exceptions • All exceptions are unchecked in Kotlin • @Throws

    is not supported in Kotlin/Native • Cannot bridge Kotlin Exceptions to Swift Errors
  25. Exception (un)Handling fun somethingThatThrows() { throw Exception(message = "Oops.") }

    ‑ Uncaught Kotlin exception: kotlin.Exception: Oops. at 3 KotlinSlideParser 0x104cb54f3 kfun:kotlin.Exception.<init>(kotlin.String)kotlin.Exception + 115 at 4 KotlinSlideParser 0x104c81dea kfun:fr.xebia.slideparser.Support.somethingThatThrows() + 122 at 5 KotlinSlideParser 0x104c81d10 KotlinSlideParser + 7440 at 6 SlideRehearser 0x104978081 _T014SlideRehearser14ViewControllerC11viewDidLoadyyF + 81 at 7 SlideRehearser 0x104978104 _T014SlideRehearser14ViewControllerC11viewDidLoadyyFTo + 36 at 8 UIKit 0x107e8646c -[UIViewController loadViewIfRequired] + 1235 ...
  26. Concurrency Kotlin/Native supports: • Workers (specific to Kotlin/Native) • Coroutines

    (as in Kotlin/JVM) • not particularly developer-friendly in K/N • high-level API (kotlinx.coroutines) not yet available
  27. Kotlin public sealed class SlideEntity { data class Page(val contents:

    List<MarkdownEntity>): SlideEntity() } public sealed class MarkdownEntity { data class Header(val contents: List<MarkdownEntity>, val level: Int): MarkdownEntity() data class Plain(val contents: String): MarkdownEntity() } public class SlideParser { public fun parsePages(string: String): List<SlideEntity>? { val result = this.pageParser().process(string) return if (result.isEmpty()) { null } else { result[0].first } } }
  28. iOS (Swift) import KotlinSlideParser // ... let parser = KSPSlideParser()

    guard let pages = parser.parsePages(string: myText) else { return } pages.first?.contents.forEach { entity in switch entity { case let header as KSPMarkdownEntityHeader: header.level // Level of the header case let plain as KSPMarkdownEntityPlain: plain.contents // Text of the entity default: break } }
  29. Android (Kotlin) import fr.xebia.slideparser.SlideParser // ... val parser = SlideParser()

    val pages = parser.parsePages(myText) pages?.first()?.contents?.forEach { when(it) { is MarkdownEntity.Header -> it.level // Level of the header is MarkdownEntity.Plain -> it.contents // Text of the entity } }
  30. Another Approach On Android, we can compile to an NDK

    Library • less developer-friendly • better performance • suitable for CPU-intensive operations
  31. Current Limitations • Still a Technology Preview • Compilation time

    • A number of known issues • Some everyday functions not available in K/N • Some types poorly translate to Swift (e.g. generics) • iOS bitcode not supported • ENABLE_BITCODE needs to be set to NO
  32. Future Evolutions • Multiplatform • a specific DSL to build

    cross-platform apps • AppCode Support • Better Objective-C header generation • kotlinx.coroutines extensions • Native interoperability with Swift (?) • And more...
  33. Other Resources • Swift is like Kotlin • Anything you

    can do, I can do better • Kotlin Blog • Deep Dive into Kotlin/Native by Andrey Breslav • Kotlin Slack
  34. Main strengths • Reuse Kotlin code you already have •

    "Feels" like Swift • Write once, run anywhere - even without the JVM! • Battle-tested, mobile-first IDEs