Kotlin Multiplatform in Production

Kotlin Multiplatform in Production

Update on the state of the Kotlin Multiplatform universe, current libraries, and how to get started.

58d1281770fe55a05a96600244ec8341?s=128

Kevin Galligan

November 19, 2018
Tweet

Transcript

  1. Kotlin Multiplatform In Production Kevin Galligan

  2. None
  3. Touchlab

  4. Community community!

  5. None
  6. What is Kotlin Multiplatform?

  7. kot·lin mul·ti·plat·form /ˌkätˈlin məltiˈplatfôrm,ˌkätˈlin məltīˈplatfôrm/ noun noun: kotlin multiplatform 1.optional,

    natively-integrated, open-source, code sharing platform, based on the popular, modern language kotlin. facilitates non-ui logic availability on many platforms.
  8. Optional Sharing Low risk. No Big Decisions.

  9. Natively Integrated smooth interop

  10. open source

  11. Code Sharing not “cross platform”

  12. popular

  13. popular

  14. popular

  15. language & tools

  16. modern

  17. Not UI well, not necessarily UI

  18. Shared UI == Failure!

  19. Shared Logic == Computers

  20. Many Platforms

  21. Kotlin

  22. Kotlin JVM

  23. Kotlin JVM JS

  24. Kotlin JVM JS Native

  25. Kotlin JVM JS Native iOS Mac Linux Windows Android/NDK Others…

  26. Kotlin JVM JS Native iOS Mac Linux Windows Android/NDK Others…

    Webassembly
  27. Kotlin JVM JS Native iOS Mac Linux Windows Android/NDK Others…

    Webassembly Many Platforms
  28. Why Kotlin? High Efficiency Low Risk Modern Language/Tools Highly Engaged

    Community
  29. mobile is easy

  30. mobile is easy

  31. Status

  32. Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7

    v0.8 v0.8.2 v0.9.3 IDE tooling! Coroutines?
  33. Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7

    v0.8 v0.8.2 v0.9.3 IDE tooling! Coroutines? K/N 1.0, Kotlin 1.3 Gradle 4.10+ Android Studio
  34. Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7

    v0.8 v0.8.2 v0.9.3 IDE tooling! Coroutines? K/N 1.0, Kotlin 1.3 Gradle 4.10+ Android Studio Other samples/libraries Production deployments Compiler plugins! MT Coroutines!
  35. Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7

    v0.8 v0.8.2 v0.9.3 IDE tooling! Coroutines? K/N 1.0, Kotlin 1.3 Gradle 4.10+ Android Studio Compiler plugins! Other samples/libraries Production deployments Paid license/debugger Reactive Library Big Production Apps Webassembly stuff? MT Coroutines!
  36. TL;DR March start getting real end of Q1

  37. SHARED CODE FOR ANDROID & IOS

  38. Common

  39. Common mainThread?

  40. expect val mainThread:Boolean

  41. expect val mainThread:Boolean actual val mainThread: Boolean get() = Looper.myLooper()

    === Looper.getMainLooper()
  42. expect val mainThread:Boolean actual val mainThread: Boolean get() = Looper.myLooper()

    === Looper.getMainLooper() actual val mainThread: Boolean get() = NSThread.isMainThread()
  43. expect val mainThread:Boolean actual val mainThread: Boolean get() = Looper.myLooper()

    === Looper.getMainLooper() actual val mainThread: Boolean get() = NSThread.isMainThread() actual val mainThread: Boolean = true
  44. expect fun currentTimeMillis():Long expect fun <B> backgroundTask(backJob:()-> B, mainJob:(B) ->

    Unit) expect fun backgroundTask(backJob:()->Unit) expect fun networkBackgroundTask(backJob:()->Unit) expect fun initContext():NativeOpenHelperFactory expect fun <T> goFreeze(a:T):T expect fun <T> T.freeze2(): T expect fun simpleGet(url:String):String expect fun logException(t:Throwable) expect fun settingsFactory(): Settings.Factory expect fun createUuid():String
  45. expect class Date { fun toLongMillis():Long } expect class DateFormatHelper(format:String){

    fun toDate(s:String):Date fun format(d:Date):String }
  46. actual class Date(val date:java.util.Date) { actual fun toLongMillis(): Long =

    date.time } actual class DateFormatHelper actual constructor(format: String) { val dateFormatter = object : ThreadLocal<DateFormat>(){ override fun initialValue(): DateFormat = SimpleDateFormat(format) } actual fun toDate(s: String): Date = Date(dateFormatter.get()!!.parse(s)) actual fun format(d: Date): String = dateFormatter.get()!!.format(d.date) }
  47. fun initPlatformClient( staticFileLoader: (filePrefix: String, fileType: String) -> String?, analyticsCallback:

    (name: String, params: Map<String, Any>) -> Unit, clLogCallback: (s: String) -> Unit) {
  48. fun initPlatformClient( staticFileLoader: (filePrefix: String, fileType: String) -> String?, analyticsCallback:

    (name: String, params: Map<String, Any>) -> Unit, clLogCallback: (s: String) -> Unit) { AppContext.initPlatformClient ({filePrefix, fileType -> loadAsset("${filePrefix}.${fileType}")}, {name: String, params: Map<String, Any> -> val event = CustomEvent(name) //Loop Answers.getInstance().logCustom(event) }, { Log.w("MainApp", it) })
  49. let appContext = AppContext() appContext.doInitPlatformClient(staticFileLoader: loadAsset, analyticsCallback: analyticsCallback, clLogCallback: csLog)

    func loadAsset(filePrefix:String, fileType:String) -> String?{ do{ let bundleFile = Bundle.main.path(forResource: filePrefix, ofType: fileType) return try String(contentsOfFile: bundleFile!) } catch { return nil } }
  50. Common

  51. JVM Native Common

  52. JVM Native Common Framework

  53. JVM Native Common Framework

  54. JVM Native Common Android Stuff Framework iOS Stuff

  55. Libraries!

  56. Jetbrains • Ktor • Kotlinx.Coroutines • Kotlinx.io • Kotlinx.serialization •

    Atomic-fu (maybe?)
  57. Community • Sqldelight • Knarch.db • Multiplatform Settings • Stately

    • OKIO2 (developing) • Timber (sort of)
  58. Community • Sqldelight • Knarch.db • Multiplatform Settings • Stately

    • OKIO2 (developing) • Timber (sort of)
  59. None
  60. SQLiter trim, lightly opinionated SQLite driver

  61. SQLit trim, lightly opinionated SQLite driver

  62. Targets Native SQLite

  63. Targets Native SQLite Native SQL Encrypted

  64. Targets Native SQLite Native SQL Encrypted Android SQLite

  65. Targets Native SQLite Native SQL Encrypted Android SQLite Android SQL

    Encrypted
  66. Targets Native SQLite Native SQL Encrypted Android SQLite Android SQL

    Encrypted JS?
  67. None
  68. None
  69. Public Service Announcement if you understand anything about native…

  70. STATE

  71. 3 Ecosystems JVM, JS, and Native

  72. Kotlin/Native State Rules

  73. Rule #1 Live state belongs to 1 thread

  74. Rule #2 Frozen state can be shared by threads

  75. No threading primitives No “synchronized”, “volatile”, etc

  76. Runtime Safety Kotlin/Native can verify safe mutability

  77. JVM/JS? See Kotlinconf keynote

  78. Short term pain Tradeoff for future

  79. How does Kotlin know?!

  80. FROZEN!

  81. FROZEN!

  82. Runtime Designation AKA a flag

  83. Call freeze()

  84. One-way operation No unfreeze()

  85. class TalkExamples{ var justCountingStuff:Int = 0 init { backgroundCall {

    //do something justCountingStuff++ }.freeze() } }
  86. class TalkExamples{ var justCountingStuff:Int = 0 init { backgroundCall {

    //do something justCountingStuff++ }.freeze() } }
  87. Usually OK Data objects should be immutable

  88. Global state more difficult Service object, large memory state

  89. Passing State

  90. DetachedObjectGraph(TransferMode.SAFE) { ListData("asdf") }

  91. val data = ListData("asdf") DetachedObjectGraph(TransferMode.SAFE) { data }

  92. private val stateBox: AtomicReference<DetachedObjectGraph<Any>> = AtomicReference( DetachedObjectGraph(mode = TransferMode.SAFE, producer

    = { mutableListOf<E>() as Any }) ) private val lock = NSLock() internal fun withLockDetached(proc: (MutableList<E>) -> MutableList<E>) { lock.lock() try { stateBox.value = DetachedObjectGraph(mode = TransferMode.SAFE, producer = { val dataList = stateBox.value.attach() as MutableList<E> proc(dataList) as Any }) } finally { lock.unlock() } }
  93. Detaching Time must visit whole graph

  94. None
  95. None
  96. None
  97. Atomics! Mutable immutable

  98. AtomicInt/AtomicLong

  99. AtomicReference Update with frozen objects

  100. val lambdas = AtomicReference<PlatformLambdas?>(null) fun initPlatformClient( staticFileLoader: (filePrefix: String, fileType:

    String) -> String?, analyticsCallback: (name: String, params: Map<String, Any>) -> Unit, clLogCallback: (s: String) -> Unit) { lambdas.value = PlatformLambdas( staticFileLoader, analyticsCallback, clLogCallback).freeze() }
  101. Stately! v0.3.1~ish

  102. Multiplatform Definitions • freeze() method and frozen info • Atomics

    (Int, Long, Reference) • K/N state-related annotations (@ThreadLocal/ @SharedImmutable) • Shared Collections!
  103. More Info and Tutorials https://github.com/touchlab/KotlinMultiplatformStuff

  104. Making a Library! a very small library

  105. Download Intellij EAP https://www.jetbrains.com/idea/nextversion/

  106. None
  107. None
  108. None
  109. None
  110. targets { fromPreset(presets.jvm, 'jvm') // This preset is for iPhone

    emulator // Switch here to presets.iosArm64 to build library for iPhone device fromPreset(presets.iosX64, 'ios') { compilations.main.outputKinds('FRAMEWORK') } }
  111. targets { fromPreset(presets.jvm, 'jvm') // This preset is for iPhone

    emulator // Switch here to presets.iosArm64 to build library for iPhone device fromPreset(presets.macosX64, 'ios') /*{ compilations.main.outputKinds('FRAMEWORK') }*/ }
  112. targets { fromPreset(presets.jvm, 'jvm') fromPreset(presets.js, 'js') fromPreset(presets.macosX64, 'macos') fromPreset(presets.iosX64, 'iosX64')

    fromPreset(presets.iosArm32, 'iosArm32') fromPreset(presets.iosArm64, 'iosArm64') }
  113. Live Coding is a Bad Idea don’t be a hero

  114. Go to Github https://github.com/kpgalligan/MyNewLibrary

  115. Much More obviously

  116. Libraries Needed • File Access • Date (310 port) •

    Mocking (and other test support) • Reactive • UI State
  117. Getting Started

  118. Join Kotlin Slack https://slack.kotlinlang.org

  119. Sample Apps the conference apps

  120. https://github.com/touchlab/DroidconKotlin/

  121. Sample Libraries Stately SQLDelight

  122. Office Hours - Kotlin Multiplatform 2pm in Coblenz

  123. None
  124. kevin@touchlab.co @kpgalligan

  125. kevin@touchlab.co @kpgalligan Join the team !