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

Challenges of Building Kotlin Multiplatform Libraries

Mohit S
March 25, 2022

Challenges of Building Kotlin Multiplatform Libraries

Mohit S

March 25, 2022
Tweet

More Decks by Mohit S

Other Decks in Programming

Transcript

  1. Mohit Sarveiya Building Kotlin Multiplatform Libraries @heyitsmohit

  2. Building Kotlin Multiplatform Libraries • Setting up KMM project •

    CI Challenges • API Design Challenges
  3. Why Kotlin Multiplatform? Android Kotlin/JVM iOS Swift/LLVM Web JS

  4. Why Kotlin Multiplatform? API API API

  5. Why Kotlin Multiplatform? Retrofit Ajax Alamofire

  6. Why Kotlin Multiplatform? Room/SQL Delight Core Data

  7. Why Kotlin Multiplatform? Business Logic Business Logic Business Logic

  8. Why Kotlin Multiplatform? MVP/MVVM/MVI ReactJs VIPER

  9. Why Kotlin Multiplatform? Shared code

  10. Why Kotlin Multiplatform? API Business Logic Analytics Cache

  11. Setting up KMM Project

  12. Use Case Show platform name Hello 
 Android

  13. Hello 
 iOS Use Case 9:41 Show platform name

  14. Greeter Use Case

  15. How to create Multiplatform app

  16. Plugin https: // plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile

  17. Project Setup Shared

  18. Project Setup Shared Android App

  19. Project Setup Shared Android App iOS App XCode Project

  20. Project Setup Shared Android App iOS App

  21. Project Setup Shared Android App iOS App Framework

  22. Project Setup Shared Android App iOS App

  23. Shared Module Structure

  24. Shared Module Shared src commonMain

  25. Shared Module Shared src commonMain androidMain

  26. Shared Module Shared src commonMain androidMain iOSMain

  27. Greeter Use Case

  28. Common Shared Module Android iOS Platform name

  29. Common expect class Platform() { val platform: String }

  30. Common expect class Platform() { val platform: String }

  31. Common expect class Platform() { val platform: String }

  32. Common expect class Platform() { val platform: String } Common

  33. Common Android Android iOS Platform name

  34. Android actual class Platform actual constructor() { actual val platform:

    String = ”Android” }
  35. Android actual class Platform actual constructor() { actual val platform:

    String = ”Android” }
  36. Android actual class Platform actual constructor() { actual val platform:

    String = ”Android” }
  37. Android actual class Platform actual constructor() { actual val platform:

    String = ”Android” } Common Android
  38. Common iOS Android iOS Platform name

  39. iOS actual class Platform actual constructor() { actual val platform:

    String = “iOS” }
  40. Common Shared Module Android iOS Platform name

  41. Common class Greeter { fun greet(): String { return "Hello

    ${Platform().platform}!" } }
  42. Common class Greeter { fun greet(): String { return "Hello

    ${Platform().platform}!" } }
  43. Using Shared Module

  44. Project Setup Shared Android App iOS App

  45. Use Case Show platform name Hello 
 Android

  46. Android App class MainActivity : AppCompatActivity() { }

  47. Android App class MainActivity : AppCompatActivity() { fun onCreate( ...

    ) { val greeting = Greeter().greet() } }
  48. Android App class MainActivity : AppCompatActivity() { fun onCreate( ...

    ) { val greeting = Greeter().greet() textView.text = greeting } }
  49. Android App class Greeter { ... } Common Source Build

  50. Use Case Hello 
 Android

  51. Android App class MainActivity : AppCompatActivity() { fun onCreate( ...

    ) { val greeting = Greeter().greet() textView.text = greeting } }
  52. Hello 
 iOS Use Case 9:41 Show platform name

  53. iOS App class Greeter { ... } Common Source Build

    Framework
  54. iOS App import SwiftUI import shared

  55. iOS App import SwiftUI import shared func greet() -> String

    { return Greeting().greeting() }
  56. iOS App import SwiftUI import shared struct ContentView: View {

    var body: some View { } }
  57. iOS App import SwiftUI import shared struct ContentView: View {

    var body: some View { Text(greet()) } }
  58. Hello 
 iOS Use Case 9:41 Show platform name

  59. Inside Objective-C Framework

  60. iOS Framework class Greeter { ... } Common Source Build

    Framework
  61. iOS Framework import SwiftUI import shared func greet() -> String

    { return Greeting().greeting() }
  62. iOS Framework Shared Base Shared Platform Shared Greeting

  63. Shared Base __attribute__((swift_name("KotlinBase"))) @interface SharedBase : NSObject ... @end;

  64. Shared Base __attribute__((swift_name("KotlinBase"))) @interface SharedBase : NSObject ... @end;

  65. iOS actual class Platform actual constructor() { actual val platform:

    String = “iOS” }
  66. Mappings https: // kotlinlang.org/docs/native-objc-interop.html#mappings

  67. Shared Platform __ attribute __ ((swift_name(“Platform"))) @interface SharedPlatform : SharedBase

    ... @end;
  68. Shared Platform __ attribute __ ((swift_name(“Platform"))) @interface SharedPlatform : SharedBase

    @property (readonly) NSString *platform 
 @end;
  69. Common class Greeter { fun greet(): String { return "Hello

    ${Platform().platform}!" } }
  70. Common @interface SharedGreeting : SharedBase - (NSString *)greeting __ attribute

    __ ((swift_name("greeting()"))); @end;
  71. Android & iOS Shared Modules

  72. Use Case Hello 
 Android 29

  73. Shared Module Shared src commonMain androidMain iOSMain

  74. Android actual class Platform actual constructor() { actual val platform:

    String = 
 “Android ${android.os.Build.VERSION.SDK_INT}" }
  75. Hello 
 iOS 14.4 Use Case 9:41

  76. Shared Module Shared src commonMain androidMain iOSMain

  77. iOS import platform.UIKit.UIDevice actual class Platform actual constructor() { actual

    val platform: String = UIDevice.currentDevice.systemName() + " " + 
 UIDevice.currentDevice.systemVersion }
  78. iOS import platform.UIKit.UIDevice actual class Platform actual constructor() { actual

    val platform: String = UIDevice.currentDevice.systemName() + " " + 
 UIDevice.currentDevice.systemVersion }
  79. Summary • How to build KMM project • Shared Module

    Setup • Inside Shared Framework
  80. CI Challenges

  81. Swift Package Manager

  82. Framework KMM Library

  83. Swift Package Manager KMM Library

  84. Multiplatform Swift Package • Gradle plugin • Generate XCFramework

  85. Multiplatform Swift Package id("com.chromaticnoise.multiplatform-swiftpackage") version "2.0.3"

  86. Multiplatform Swift Package multiplatformSwiftPackage { swiftToolsVersion(“5.5") targetPlatforms { iOS {

    v("13") } } }
  87. Multiplatform Swift Package ./gradlew createSwiftPackage

  88. KMM Library XCEFramework

  89. Projects/KMMProject Code ! Issues Pull Requests KMMLibrary.xcframework 1 commit 4c28f942

    13 hours ago Package.swift KMMLibrary-1.0.zip README.md
  90. Choose Package Repository Search or enter package repository URL Name

    Last Updated Owner Projects(Github) KMMPackage Today 13:00 user
  91. Add Package to Project Choose package and targets Kind Add

    to Target KMMLibrary Library TestKMMLibrary Package Product
  92. Steps • Create XCEFramework • Consume using Swift Package Manager

  93. Build Automation

  94. KMM Library bdae142 .. main 50157a .. d89f145 .. f0ddfb

    ..
  95. bdae142 .. main 50157a .. d89f145 .. f0ddfb ..

  96. KMM Library Jar XCEFramework

  97. KMM Library Jar XCEFramework Artifactory

  98. Artifactory

  99. Build Automation • Setup CI to create artifcats • Use

    artifacts from repository like Artifactory
  100. API Design Challenges

  101. Flows

  102. Common fun getData(): Flow<Data>

  103. Android val flow = getData() flow.collect { }

  104. iOS getData( collector: T ## Kotlinx_coroutines_coreFlowCollector, completionHandler: (KotlinUnit?, Error?) ->

    Void )
  105. Common class CFlow internal constructor( val origin: Flow ) :

    Flow by origin { fun watch(block: (T) -> Unit) { } }
  106. Common class CFlow internal constructor( val origin: Flow ) :

    Flow by origin { fun watch(block: (T) -> Unit) { onEach { block(it) } launchIn(CoroutineScope( ... )) } }
  107. Common fun Flow<T>.wrap(): CFlow<T> = CFlow(this)

  108. iOS flow .wrap() .watch { data ->
 }

  109. Building Kotlin Multiplatform Libraries • Setting up KMM project •

    CI Challenges • API Design Challenges
  110. Thank You! www.codingwithmohit.com @heyitsmohit