Kotlin Multiplatform

Kotlin Multiplatform

Introduction to Kotlin Multiplatform that I gave at Kotlin Everywhere in Minneapolis on October 5, 2019

108056ccba92f98fdbbabad534537573?s=128

Bryan Herbst

October 05, 2019
Tweet

Transcript

  1. Kotlin Multiplatform Bryan Herbst

  2. Beware: Kotlin MPP is under development

  3. Why cross-platform?

  4. None
  5. None
  6. None
  7. None
  8. None
  9. None
  10. More platforms = More developers More money More code More

    bugs
  11. More platforms = More developers More money More code More

    bugs
  12. More platforms = More developers More money More code More

    bugs
  13. More platforms = More developers More money More code More

    bugs
  14. Fewer platforms = Fewer developers? Less money? Less code? Fewer

    bugs?
  15. User Experience is table stakes

  16. User Experience is table stakes How native is the UI?

    How responsive is the app?
  17. User Experience is table stakes How native is the UI?

    How responsive is the app?
  18. Developer happiness is critical

  19. Developer happiness is critical Speed of platform updates Interop with

    native Interop with existing code Language
  20. Developer happiness is critical Speed of platform updates Interop with

    native Interop with existing code Language
  21. Developer happiness is critical Speed of platform updates Interop with

    native Interop with existing code Language
  22. Developer happiness is critical Speed of platform updates Interop with

    native Interop with existing code Language
  23. Cross-platform architecture

  24. What to share?

  25. As much (or as little) as you want

  26. Embrace platform differences, but provide a consistent core

  27. Assumption: you already have an iOS & Android app

  28. Feature UI Logic Data

  29. Feature UI Logic Data Data models, Networking

  30. Feature UI Logic Data Great place to start!

  31. Feature UI Logic Data ViewControllers, ViewModels

  32. Feature UI Logic Data Trickier

  33. Feature UI Logic Data Layouts, Views

  34. Feature UI Logic Data Probably not worth it

  35. What is platform dependent?

  36. What is platform dependent? Almost everything the user sees

  37. What is platform dependent? Logging

  38. What is platform dependent? Disk storage

  39. What is platform dependent? Networking

  40. Shared Library Common Android iOS

  41. Shared Library Common Android iOS Android App iOS App

  42. Shared Library Common Android iOS Android App iOS App lib

    lib
  43. Mono Repo Common Android iOS Android App iOS App lib

    lib
  44. Shared Library Common Android iOS Android App iOS App lib

    lib
  45. How Kotlin MPP works

  46. kotlinc Main.kt

  47. kotlinc Frontend Intermediate representation Backend

  48. kotlinc Frontend Intermediate representation Backend

  49. kotlinc Frontend Intermediate representation Backend

  50. kotlinc Frontend Intermediate representation Kotlin JVM

  51. kotlinc Frontend Intermediate representation Kotlin JS

  52. kotlinc Frontend Intermediate representation Kotlin Native

  53. Kotlin JVM Output is bytecode

  54. Kotlin JVM 100% interoperability

  55. Kotlin JS Output is JS

  56. Kotlin JS Output is JS

  57. Kotlin JS - libraries Dukat binds strongly-typed libraries

  58. Kotlin JS - libraries dynamic type supports loose typing

  59. Dynamic val dyn: dynamic = ...

  60. Dynamic Disables type checking

  61. Dynamic Can call any property or function

  62. Kotlin Native Outputs native binary

  63. Kotlin Native Outputs native binary Executable

  64. Kotlin Native Outputs native binary Executable C library

  65. Kotlin Native Outputs native binary Executable C library Apple framework

  66. Kotlin Native Compiled with LLVM

  67. Kotlin Native arm32, arm64 x86, x86_64 mingw x86_64 MIPS, rPi

    wasm32
  68. Native libraries 1. Create .def 2. Cinterop creates kotlin bindings

    of C/C++ code
  69. Native libraries 1. Create .def 2. cinterop produces Kotlin bindings

  70. Native libraries Platform libraries

  71. Native libraries Platform libraries e.g. Open GL, objc, posix

  72. Swift?

  73. Kotlin Multiplatform

  74. Main.kt Frontend IR JVM Native JS

  75. Let’s get started!

  76. plugins { id 'org.jetbrains.kotlin.multiplatform' version '1.3.50’ }

  77. kotlin { jvm() // Creates a JVM target }

  78. kotlin { iosArm32("ios32") iosArm64("ios64") configure([ios32, ios64]) { binaries.framework { baseName

    = "SharedCode" } } }
  79. kotlin { iosArm32("ios32") iosArm64("ios64") configure([ios32, ios64]) { binaries.framework { baseName

    = "SharedCode" } } }
  80. kotlin { iosArm32("ios32") iosArm64("ios64") // Simulator iosX64("iosX64") }

  81. val sdk = System.getenv("SDK_NAME") if (sdk?.startsWith("iphoneos")) { iosX64("iosX64") } else

    { //.... }
  82. Carthage or CocoaPods

  83. plugins { id("org.jetbrains.kotlin.native.cocoapods") } kotlin { cocoapods { summary =

    "Shared library" homepage = "http://github.com/shared-lib" } }
  84. Time to write some code

  85. Android Notes UI NotesView Model Note (model) Note API iOS

    Notes UI NotesView Controller Note (model) Note API
  86. Android Notes UI NotesView Model Note API iOS Notes UI

    NotesView Controller Note API Shared Note (model)
  87. Note JSON { content: "Hello", status: "Pinned" }

  88. iOS struct Note { let content: String let status: String

    } Android data class Note( val content: String, val status: Status ) enum class Status { }
  89. iOS struct Note { let content: String let status: String

    } Android data class Note( val content: String, val status: Status ) enum class Status { }
  90. iOS struct Note { let content: String let status: String

    } Android data class Note( val content: String, val status: Status ) enum class Status { }
  91. data class Note( val content: String, val status: String )

    Shared
  92. data class Note( val content: String, val status: String )

    Android
  93. __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Note"))) @interface SharedNote : KotlinBase @property (readonly) NSString *

    content; @property (readonly) NSString * status; @end; iOS
  94. __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Note"))) @interface SharedNote : KotlinBase @property (readonly) NSString *

    content; @property (readonly) NSString * status; @end; iOS
  95. __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Note"))) @interface SharedNote : KotlinBase @property (readonly) NSString *

    content; @property (readonly) NSString * status; @end; iOS – Objective C
  96. class Note: KotlinBase { private(set) var content: String? private(set) var

    status: String? } iOS – Swift
  97. Android Notes UI NotesView Model Note API iOS Notes UI

    NotesView Controller Note API Shared Note (model)
  98. Android Notes UI NotesView Model iOS Notes UI NotesView Controller

    Shared Note (model) Note API
  99. Serialization Kotlinx.serialization

  100. @Serializable data class Note( val content: String val status: String

    )
  101. Json.nonstrict .stringify( Note.serializer(), note )

  102. Json.nonstrict .parse( Note.serializer(), jsonString )

  103. Json.nonstrict .parse( Note.serializer().list, jsonString )

  104. Serialization is multiplatform!

  105. Serialization is multiplatform! Charsets, input streams, buffers

  106. commonMain { dependencies { implementation "serialization-runtime-common" } }

  107. jvmMain { dependencies { implementation "serialization-runtime" } }

  108. nativeMain { dependencies { implementation "serialization-runtime-native" } }

  109. Networking KTOR

  110. Under the hood - engines Android: OkHttp, HttpUrlConnection

  111. Under the hood - engines Android: OkHttp, HttpUrlConnection iOS: NSUrlSession

  112. class NoteApi() { private val client = HttpClient() suspend fun

    fetchNote(): String = client.get<String>("http://...") }
  113. How do we support different platforms?

  114. common/PlatformName.kt expect fun getPlatform(): String

  115. android/PlatformName.kt actual fun getPlatform()= "Android"

  116. ios/PlatformName.kt actual fun getPlatform() = "iOS"

  117. Common/KeyValueStore.kt expect class KeyValueStore() { fun setString(key: String, value: String)

    fun getString(key: String): String }
  118. android/KeyValueStore.kt actual class KeyValueStore() { private val prefs: SharedPreferences actual

    fun setString() //... actual fun getString() //... }
  119. ios/KeyValueStore.kt actual class KeyValueStore() { private val userDefaults: NSUserDefaults actual

    fun setString() //... actual fun getString() //... }
  120. expect interface Closeable { fun close() } actual typealias Closeable

    = java.io.Closeable
  121. Platform differences

  122. None
  123. Unsupported in Swift/Obj-C Suspend functions Inline classes

  124. Asyncronous work

  125. Coroutines Only single-threaded code is currently supported for Kotlin/Native

  126. Exceptions

  127. Exceptions All Kotlin exceptions are unchecked

  128. Exceptions All Kotlin exceptions are unchecked Swift only has checked

    errors
  129. Exceptions Annotate with @Throws

  130. Primitive types Int -> KotlinInt

  131. Primitive types Int -> KotlinInt (NSNumber)

  132. Generics

  133. Generics Experimental for Kotlin Native

  134. Generics Experimental for Kotlin Native extraOpts "-Xobjc-generics"

  135. Kotlin: class Generic<T> Swift: class Generic<T>

  136. Kotlin: class Generic<T> Swift: class Generic<T>

  137. Kotlin: class Generic<T>(val item: T) Swift: class Generic<T> { let

    item: T? }
  138. Kotlin: class Generic<T>(val item: T) Swift: class Generic<T> { let

    item: T? } ?
  139. Kotlin: class Generic<T: Any>(val item: T) Swift: class Generic<T> {

    let item: T }
  140. Thanks!