$30 off During Our Annual Pro Sale. View Details »

Sharing is Caring- Getting Started with Kotlin Multiplatform

Sharing is Caring- Getting Started with Kotlin Multiplatform

*** Presented in KotlinConf 2019, Droidcon Singapore 2019, Droidcon Vietnam 2019 ***

As Android developers, often we work with a backend service. Often in our team, there is an iOS project or a Javascript project, with similar functionality, that is being developed by our teammate developers next door. How fun would it be to write Kotlin code once and share it with all platforms? It will save us so much time and effort in implementation and testing! Please meet Kotlin Multiplatform! It is experimental, and yet very powerful and awesome.

This session will focus on creating a full-stack Kotlin project that fits an Android app and a backend Kotlin component. You’ll learn how to share code between the components to build more efficient and robust applications. And your teammate next door will thank you as well 🙂

Britt Barak

July 07, 2019
Tweet

More Decks by Britt Barak

Other Decks in Programming

Transcript

  1. Copenhagen
    Denmark
    SHARING IS CARING
    INTRO TO KOTLIN MULTIPLATFORM
    BRITT BARAK
    NEXMO, VONAGE
    @brittBarak

    View Slide

  2. Copenhagen
    Denmark
    SHARING IS CARING
    INTRO TO KOTLIN MULTIPLATFORM
    BRITT BARAK
    NEXMO, VONAGE

    View Slide

  3. SHARING IS CARING

    View Slide

  4. SHARING IS CARING

    View Slide

  5. Drinks
    Gift
    Card
    Cake
    Balloons
    Emma`s GoodBye
    @brittBarak

    View Slide

  6. Drinks
    Gift
    Card
    Cake
    Balloons
    Emma`s GoodBye
    @brittBarak

    View Slide

  7. Drinks
    Emma`s GoodBye
    Balloons
    Britt: red are the best!
    Gift
    @brittBarak

    View Slide

  8. Drinks
    Emma`s GoodBye
    Balloons
    Jurgo: will go later
    Gift
    Britt: red are the best!
    @brittBarak

    View Slide

  9. Drinks
    Emma`s GoodBye
    Balloons
    Jurgo: good?
    Jurgo: will go later
    Britt: red are the best!
    @brittBarak

    View Slide

  10. Drinks
    Emma`s GoodBye
    Balloons
    On A Call :
    Jurgo & Britt
    Jurgo: good?
    Jurgo: will go later
    Britt: red are the best!
    @brittBarak

    View Slide

  11. Data Model
    Conversation

    View Slide

  12. Conversation
    member
    member
    member
    member
    member
    member
    member member
    member member
    Data Model

    View Slide

  13. Conversation
    member
    member
    member
    member
    member
    member
    member member
    member
    Data Model
    member

    View Slide

  14. Data Model
    Conversation
    Event
    Event
    Event
    Event
    Event
    Event
    Event

    View Slide

  15. Data Model
    Conversation
    Prosecco!
    Call
    Balloons
    Is it good?
    Drinks
    Will go tmrw
    Red is best!
    More prosecco!

    View Slide

  16. Emma`s GoodBye Conversation
    Drinks
    Drinks
    Balloons
    Balloons
    Red is best!
    Red is best!
    Will go tmrw
    Will go tmrw
    Call
    Call
    Prosecco!
    Prosecco!
    Is it good?
    Is it good?
    More prosecco!
    More prosecco!

    View Slide

  17. Conversation
    Drinks
    Balloons
    Red is best!
    Will go tmrw
    Call
    Prosecco!
    Is it good?
    More prosecco!
    Balloons
    Cake
    Balloons
    Emma`s GoodBye
    Red is best!
    Will go tmrw
    Call
    Prosecco!
    Is it good?
    More prosecco!
    Drinks

    View Slide

  18. Parse
    Sort
    Present
    OnNewEvent()
    @brittBarak

    View Slide

  19. Parse
    Sort
    Present
    @brittBarak

    View Slide

  20. Parse
    Sort
    Present
    @brittBarak

    View Slide

  21. Parse
    Sort
    Present Present
    Present
    @brittBarak

    View Slide

  22. Parse
    Sort
    Present Present
    Present
    Parse
    Sort
    Parse

    Sort
    @brittBarak

    View Slide

  23. Parse
    Sort
    Present Present
    Present
    @brittBarak

    View Slide

  24. @brittBarak
    Parse
    Sort
    Present Present
    Present
    Kotlin Multiplatform

    View Slide

  25. @brittBarak
    Parse
    Sort
    Present Present
    Present
    Kotlin Multiplatform
    Share only
    what you want,
    when you want.

    View Slide

  26. Parse
    Sort
    Present Present
    Present
    Kotlin Multiplatform
    @brittBarak

    View Slide

  27. Common
    Present Present
    Present
    Kotlin Multiplatform
    @brittBarak

    View Slide

  28. Common
    Target Target
    Target
    Kotlin Multiplatform
    @brittBarak

    View Slide

  29. @brittBarak

    View Slide

  30. @brittBarak
    JVM

    View Slide

  31. @brittBarak
    JVM
    *.class

    View Slide

  32. @brittBarak
    JVM
    *.class
    *.java
    MyClass.java

    View Slide

  33. @brittBarak
    JVM
    *.class
    *.java javac
    MyClass.java MyClass.class

    View Slide

  34. @brittBarak
    JVM
    *.class
    *.java
    *.kt
    javac

    View Slide

  35. @brittBarak
    JVM
    *.class
    *.java
    *.kt
    javac
    MyFile.kt

    View Slide

  36. @brittBarak
    JVM
    *.class
    *.java
    *.kt kotlinc
    javac
    MyFileKt.java
    MyFile.kt

    View Slide

  37. @brittBarak
    JVM
    *.class
    *.java
    *.kt kotlinc
    javac
    MyFileKt.java
    MyFile.kt
    InnerClass.java

    View Slide

  38. @brittBarak
    JVM
    *.class
    *.java
    *.kt kotlinc
    javac
    MyFileKt.java
    MyFile.kt
    InnerClass.java

    View Slide

  39. @brittBarak
    JVM
    *.class
    *.java
    *.kt kotlinc
    javac
    MyFile.kt
    InnerClass.class
    MyFileKt.class

    View Slide

  40. Common
    Target Target
    Target
    Kotlin Multiplatform
    @brittBarak

    View Slide

  41. Common
    kotlin/
    JVM Target
    Target
    Kotlin Multiplatform
    @brittBarak

    View Slide

  42. Common
    kotlin/
    JVM Target
    Target
    Kotlin Multiplatform
    Android
    Backend Desktop
    @brittBarak

    View Slide

  43. Common
    kotlin/
    JVM kotlin/
    JS
    Target
    Kotlin Multiplatform
    Web browser
    Node.JS
    Android
    Backend Desktop
    @brittBarak

    View Slide

  44. Common
    kotlin/
    JVM kotlin/
    JS
    kotlin/
    Native
    Kotlin Multiplatform
    Web browser
    Node.JS
    Android
    Backend Desktop
    @brittBarak

    View Slide

  45. Common
    kotlin/
    JVM kotlin/
    JS
    kotlin/
    Native
    Kotlin Multiplatform
    Android
    Backend Desktop
    Web browser
    Node.JS
    iOS
    Android native
    Desktop native
    Web assembly
    @brittBarak

    View Slide

  46. Get Started
    @brittBarak

    View Slide

  47. 1. Add plugin
    plugins {
    id("org.jetbrains.kotlin.multiplatform").version("1.3.61")
    }
    build.gradle
    @brittBarak

    View Slide

  48. 2. Set targets
    @brittBarak

    View Slide

  49. Supported platforms
    • jvm —> Kotlin/JVM
    • android —> Android applications and libraries
    • js —> Kotlin/JS
    • Kotlin/Native —>
    @brittBarak

    View Slide

  50. Supported platforms (Native)
    •androidNativeArm32 , androidNativeArm64 —> Android NDK
    •iosArm32, iosArm64, iosX64 —> iOS
    •linuxArm32Hfp, linuxMips32, linuxMipsel32, linuxX64 —> Linux
    •macosX64 —> MacOS
    •mingwX64 —> Windows
    •wasm32 —> WebAssembly
    @brittBarak

    View Slide

  51. 2. Set targets
    @brittBarak

    View Slide

  52. build.gradle
    plugins {…}
    kotlin {
    jvm()
    js("nodeJs") { … }
    }
    @brittBarak
    2. Set targets

    View Slide

  53. build.gradle
    plugins {…}
    kotlin {
    jvm()
    js("nodeJs") { … }
    js(“browser") { … }
    }
    @brittBarak
    2. Set targets

    View Slide

  54. For Android
    @brittBarak

    View Slide

  55. build.gradle
    kotlin {
    android()
    }
    @brittBarak

    View Slide

  56. plugins {
    id("org.jetbrains.kotlin.multiplatform").version("1.3.61")
    id(“com.android.application") // or (“com.android.library")
    }
    kotlin {
    android()
    }
    @brittBarak

    View Slide

  57. plugins {
    id("org.jetbrains.kotlin.multiplatform").version("1.3.61")
    id(“com.android.application") // or (“com.android.library”)
    }
    android { ... }
    kotlin {
    android()
    }
    @brittBarak

    View Slide

  58. 3. Source sets
    @brittBarak

    View Slide

  59. 3. Source sets
    sourceSets {
    common{}
    android{}
    jvm{}
    }
    @brittBarak

    View Slide

  60. 3. Source sets
    sourceSets {
    common{}
    android{}
    jvm{}
    }
    @brittBarak

    View Slide

  61. 3. Source sets
    sourceSets {
    commonMain{}
    commonTest{}
    androidMain{}
    androidTest{}
    }
    @brittBarak

    View Slide

  62. 3. Source sets
    sourceSets {
    commonMain {
    dependencies {
    implementation
    ‘org.jetbrains.kotlin:kotlin-stdlib-common’
    //…
    }
    }
    commonTest{…}
    }
    @brittBarak

    View Slide

  63. sourceSets {
    commonMain {…}
    commonTest{…}
    androidMain {
    dependencies {
    implementation
    "androidx.lifecycle:lifecycle-extensions:2.0.0"
    implementation ‘com.nexmo.android:client-sdk:1.0.0'
    }
    }
    androidTest {..}
    3. Source sets
    @brittBarak

    View Slide

  64. sourceSets {
    commonMain {…}
    commonTest{…}
    androidMain {
    dependencies {
    implementation
    'androidx.lifecycle:lifecycle-extensions:2.0.0'
    implementation ‘com.nexmo.android:client-sdk:1.0.0'
    }
    }
    androidTest {..}
    3. Source sets
    @brittBarak

    View Slide

  65. Project Structure
    /src
    commonMain
    commonTest
    androidMain
    androidTest
    iosMain
    iosTest

    View Slide

  66. app—> common
    @brittBarak

    View Slide

  67. common:
    Parse
    Sort
    app:
    Present
    on New Event()
    @brittBarak

    View Slide

  68. app
    val eventListener: NexmoEventListener = object {
    override fun onCustomEvent(event: NexmoEvent) {
    parseTextEvent(event.id, event.text,
    this@ListActivity)
    }
    @brittBarak

    View Slide

  69. app
    val eventListener: NexmoEventListener = object {
    override fun onCustomEvent(event: NexmoEvent) {
    parseTextEvent(event.id, event.text,
    this@ListActivity)
    }
    @brittBarak

    View Slide

  70. app
    val eventListener: NexmoEventListener = object {
    override fun onCustomEvent(event: NexmoEvent) {
    processCustomEvent(event, this@ListActivity)
    }

    View Slide

  71. fun processCustomEvent(event, presenter) {
    }
    commonMain
    Balloon
    @brittBarak

    View Slide

  72. fun processCustomEvent(event, presenter) {
    val customEvent =
    Json.nonstrict.
    parse(MyCustomEvent.serializer(), event)
    }
    commonMain
    Drinks
    Balloon
    @brittBarak

    View Slide

  73. fun processCustomEvent(event, presenter) {
    val customEvent = …
    when (customEvent.type) {
    TYPE_ITEM_ADDED -> {
    presenter.
    handleItemAdded(customEvent)
    }
    }
    }
    commonMain
    Drinks
    Balloon
    @brittBarak

    View Slide

  74. fun processCustomEvent(event, presenter) {
    val customEvent = …
    when (customEvent.type) {
    TYPE_ITEM_ADDED -> {
    presenter.
    handleItemAdded(customEvent)
    }
    }
    }
    commonMain
    Drinks
    Balloon
    @brittBarak

    View Slide

  75. fun processCustomEvent(event, presenter) {
    val customEvent = …
    when (customEvent.type) {
    TYPE_ITEM_ADDED -> {
    presenter.
    handleItemAdded(customEvent)
    }
    }
    }
    commonMain
    Balloon
    @brittBarak
    Drinks

    View Slide

  76. fun processCustomEvent(event, presenter) {
    val customEvent = …
    when (customEvent.type) {
    TYPE_ITEM_ADDED -> {}
    TYPE_TEXT -> {
    }
    }
    }
    commonMain
    Drinks
    Balloon
    “Hi!”
    @brittBarak

    View Slide

  77. fun processCustomEvent(event, presenter) {
    val customEvent = …
    when (customEvent.type) {
    TYPE_ITEM_ADDED -> {}
    TYPE_TEXT -> {

    presenter.handleNewMessage
    (customEvent, position)
    }
    }
    }
    commonMain
    Drinks
    Balloon
    @brittBarak
    “Hi!”

    View Slide

  78. interface EventsPresenter {
    fun handleItemAdded(event: MyCustomEvent)
    fun handleNewMessage(event: MyCustomEvent, position: Int)
    }

    commonMain
    @brittBarak

    View Slide

  79. override fun handleNewMessage(event: MyCustomEvent, position: Int)
    {
    val itemUiModel = uiModel.items[position]
    itemUiModel?.events?.addItem(EventUiModel(event))
    rvItems.adapter?.notifyItemChanged(position)
    }

    app
    @brittBarak

    View Slide

  80. override fun handleNewMessage(event: MyCustomEvent, position: Int)
    {
    //…
    recyclerview.adapter.notifyItemChanged(position)
    }

    app
    @brittBarak

    View Slide

  81. Skipping Presenter?
    @brittBarak

    View Slide

  82. common —> app
    @brittBarak

    View Slide

  83. expect / actual
    @brittBarak

    View Slide

  84. A word about
    architecture
    @brittBarak

    View Slide

  85. Data
    Domain
    Presentation

    View Slide

  86. Data
    Domain
    Presentation
    Platform Common
    expect/actual
    DataModel
    UseCase
    UiModel
    View
    Repository

    View Slide

  87. AddItem
    @brittBarak

    View Slide

  88. Android
    btnAdd.setOnClickListener {
    //…
    uiModel.conversationLiveData.
    value?.let { it ->
    AddItem().execute(
    tilItemName.editText?.text.toString())
    }
    }
    @brittBarak

    View Slide

  89. Android
    btnAdd.setOnClickListener {
    //…
    uiModel.conversationLiveData.
    value?.let { it ->
    AddItem().execute(
    tilItemName.editText?.text.toString())
    }
    }
    @brittBarak

    View Slide

  90. Android
    btnAdd.setOnClickListener {
    //…
    uiModel.conversationLiveData.
    value?.let { it ->
    AddItem().execute(itemName)
    }
    }
    @brittBarak

    View Slide

  91. Common/ AddItem.kt
    @brittBarak

    View Slide

  92. Common/ AddItem.kt
    fun execute(itemName: String) {
    val eventJson = createEventJson(itemName)
    sendCustomText(eventJson)
    }
    expect fun sendCustomText(eventJson: String)
    @brittBarak

    View Slide

  93. Common/ AddItem.kt
    fun execute(itemName: String) {
    val eventJson = createEventJson(itemName)
    sendCustomText(eventJson)
    }
    expect fun sendCustomText(eventJson: String)
    @brittBarak

    View Slide

  94. Common/ AddItem.kt
    fun execute(itemName: String) {
    val eventJson = createEventJson(itemName)
    sendCustomText(eventJson)
    }
    expect fun sendCustomText(eventJson: String)
    @brittBarak

    View Slide

  95. Common/ AddItem.kt
    fun execute(itemName: String) {
    val eventJson = createEventJson(itemName)
    sendCustomText(eventJson)
    }
    expect fun sendCustomText(eventJson: String)
    @brittBarak

    View Slide

  96. android/ AddItem.kt
    actual fun sendCustomText(eventJson: String) {
    conversation?.sendText(eventJson, listener)
    }
    @brittBarak

    View Slide

  97. android/ AddItem.kt
    actual fun sendCustomText(eventJson: String) {
    conversation?.sendText(eventJson, listener)
    }
    @brittBarak

    View Slide

  98. ios/ AddItem.kt
    actual fun sendCustomText(eventJson: String) {
    activeConversation?
    .sendText(eventJson, completion: …
    //…
    }
    }
    @brittBarak

    View Slide

  99. JVM/ AddItem.kt
    actual fun sendCustomText(eventJson: String) {
    coroutineScope.launch(ApplicationDispatcher) {
    try {
    nexmoApiClient.post {
    url(pathSendEvent)
    body = TextContent(eventJson,
    ContentType.Application.Json)
    }
    // …
    }
    }
    @brittBarak

    View Slide

  100. JVM/ AddItem.kt
    actual fun sendCustomText(eventJson: String) {
    coroutineScope.launch(ApplicationDispatcher) {
    try {
    nexmoApiClient.post {
    url(pathSendEvent)
    body = TextContent(eventJson,
    ContentType.Application.Json)
    }
    // …
    }
    }
    @brittBarak

    View Slide

  101. JVM/ AddItem.kt
    actual fun sendCustomText(eventJson: String) {
    coroutineScope.launch(ApplicationDispatcher) {
    try {
    nexmoApiClient.post {
    url(pathSendEvent)
    body = TextContent(eventJson,
    ContentType.Application.Json)
    }
    // …
    }
    }
    @brittBarak

    View Slide

  102. expect / actual

    View Slide

  103. 1. Same location
    @brittBarak
    expect / actual
    Common/
    AddItem.kt
    android/
    AddItem.kt
    ios/
    AddItem.kt
    js/
    AddItem.kt

    View Slide

  104. 1. Same location
    2. Same signature
    @brittBarak
    expect / actual

    View Slide

  105. 1. Same location
    2. Same signature
    @brittBarak
    expect / actual
    expect fun sendCustomText(eventJson: String)
    actual fun sendCustomText(eventJson: String)

    View Slide

  106. What can I use?
    @brittBarak

    View Slide

  107. Packages

    View Slide

  108. Packages

    View Slide

  109. Libraries
    •KotlinX (serialsation)
    •Ktor (networking)
    •Coroutines (async)
    •SQKDelight (persistency)
    •more…
    • https://github.com/AAkira/Kotlin-Multiplatform-Libraries

    View Slide

  110. KotlinConf-19 sessions
    Today
    • Kotlin Multiplatform In Action/ Alexandr Pogrebnyak - 14:00, Aud15
    • Bridge The Physical World: Kotlin/Native On Raspberry Pi/ Qian Jin - 14:00, Aud12
    • Your Multiplatform Kaptain Has Arrived/ Ahmed El-Helw - 15:00 , Aud12
    • Shipping A Mobile Multiplatform Project On Ios & Android/ Ben Asher, Alec Strong - 16:15 Keynote
    • Kotlin Native Concurrency Explained/ Kevin Galligan- 17:15 , Aud12
    Tomorrow:
    • I Walk The Line: What Parts Of An App Should Be In Kotlin Native…/Ellen Shapiro - 10:15, Aud 15
    • The State Of Kotlin/Js / Sebastian Aigner - 13:00, Aud 15
    • Going Native/ Ana Redmond - 14:00, Aud15
    • Effective Kotlin-Swift Interoperability / John Rodriguez- 16:15 , Aud11
    Hands On Labs - Preparing Your Kotlin Multiplatform Development Environment/ Big Nerd Ranch - 16:15

    View Slide

  111. Sum up
    •Share what you want, when you want.
    •Experimental
    •Prepare to explore
    •Popular (in a good way!)
    •Growing, evolving, improving

    View Slide

  112. Keep Sharing and caring

    View Slide

  113. Keep Sharing and caring
    Thank you!
    @BrittBarak
    Join the goodbye party:)

    View Slide

  114. #KotlinConf
    THANK YOU
    AND
    REMEMBER
    TO VOTE
    Britt Barak @brittBarak

    View Slide