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

Building Kotlin Multiplatform Apps

Mohit S
February 27, 2021

Building Kotlin Multiplatform Apps

Kotlin multiplatform is a technology that allows you to share code between Android and iOS. In this talk, we will do a walk through on how to structure and setup a project for Android and iOS. We'll will explore possible architectures that could fit with multiplatform development. We also look at any limitations that you may come across along the way. By the end of the talk, you will have a good starting point to build multiplatform apps.

Mohit S

February 27, 2021
Tweet

More Decks by Mohit S

Other Decks in Programming

Transcript

  1. Building Kotlin Multiplatform Apps • Why Kotlin Multiplatform? • How

    to build KMM project • Networking & Caching • KMM Libraries
  2. Android App class MainActivity : AppCompatActivity() { fun onCreate( ...

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

    ) { val greeting = Greeter().greet() textView.text = greeting } }
  4. iOS App import SwiftUI import shared struct ContentView: View {

    var body: some View { Text(greet()) } }
  5. Android actual class Platform actual constructor() { actual val platform:

    String = 
 “Android ${android.os.Build.VERSION.SDK_INT}" }
  6. iOS import platform.UIKit.UIDevice actual class Platform actual constructor() { actual

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

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

    Setup • Inside Shared Framework
  9. Networking Dependencies sourceSets { val commonMain by getting { dependencies

    { implementation("io.ktor:ktor-client-core:$ktorVersion") } } } }
  10. Networking Dependencies sourceSets { val androidMain by getting { dependencies

    { implementation(“io.ktor:ktor-client-android:$ktorVersion") } } } }
  11. Networking Dependencies sourceSets { val iOSMain by getting { dependencies

    { implementation(“io.ktor:ktor-client-ios:$ktorVersion”) } } } }
  12. Kotlin/Kotlin.serialization Code ! Issues Pull Requests Kotlin Multiplatform / multi-formation

    reflectionless • Supports Kotlin classes marked as @Serializable. • Provides JSON, Protobuf, CBOR, Hocon and Properties formats. • Complete multiplatform support: JVM, JS and Native. Gradle Build passing
  13. Using Ktor class ApiClient { private val httpClient = HttpClient

    { install(JsonFeature) { val json = Json { ignoreUnknownKeys = true } serializer = KotlinxSerializer(json) } } }
  14. Using Ktor class ApiClient { private val httpClient = HttpClient

    { install(JsonFeature) { val json = Json { ignoreUnknownKeys = true } serializer = KotlinxSerializer(json) } } }
  15. Coroutines class ApiClient { suspend fun getUsers(): List<User> { return

    httpClient.get(API_ENDPOINT) } val API_ENDPOINT = “https: // api.com/users” }
  16. Using Client on Android class MyViewModel { val coroutineScope =

    CoroutineScope(Dispatchers.Main) override fun onCreate() { val apiClient = ApiClient() }
  17. Using Client on Android class MyViewModel { val coroutineScope =

    CoroutineScope(Dispatchers.Main) override fun onCreate() { val apiClient = ApiClient() coroutineScope.launch { } }
  18. Using Client on Android class MyViewModel { val coroutineScope =

    CoroutineScope(Dispatchers.Main) override fun onCreate() { val apiClient = ApiClient() coroutineScope.launch { val users = apiClient.getUsers() ... } }
  19. Using Client on iOS class ViewModel { let apiClient: ApiClient

    func loadUsers() { apiClient.getUsers(completionHandler: { users, error in ...
 } }) } }
  20. iOS Framework - (void)getUsers:(completionHandler:( 
 void (^)(NSArray<SharedUser *> * _Nullable,

    NSError * _Nullable))completionHandler __ attribute __ ((swift_name("getUsers(completionHandler:)"))); @end;
  21. iOS Framework __ attribute __ ((swift_name("User"))) @interface SharedUser : SharedBase

    @property (readonly) NSString *name 
 __ attribute __ ((swift_name("name"))); @property (readonly) NSString *location 
 __ attribute __ ((swift_name("location"))); @end;
  22. Networking Dependencies sourceSets { val commonMain by getting { dependencies

    { implementation("com.squareup.sqldelight:runtime:1.4.2") } } } }
  23. Networking Dependencies sourceSets { val androidMain by getting { dependencies

    { implementation(“com.squareup.sqldelight:android-driver:1.4.2") } } } }
  24. Networking Dependencies sourceSets { val iOSMain by getting { dependencies

    { implementation(“com.squareup.sqldelight:native-driver:1.4.2”) } } } }
  25. SQL Queries CREATE TABLE User ( id TEXT NOT NULL

    PRIMARY KEY, name TEXT NOT NULL, Location TEXT NOT NULL );
  26. class Database() { private val database = AppDatabase() fun getUsers():

    List<User> { return database.selectUsers().executeAsList() } } Configure SQL Delight
  27. class Database() { private val database = AppDatabase() fun insertUser(user:

    User) { database.insertUser( id = user.id, name = user.name, location = user.location ) } Configure SQL Delight
  28. SQL Delight CREATE TABLE USER { ... } Queries Build

    Generated class Database { ... }
  29. API Client class ApiClient { suspend fun getUsers(): List<User> {

    return httpClient.get(API_ENDPOINT) } val API_ENDPOINT = “https: // api.com/users” }
  30. Caching class ApiClient { suspend fun getUsers(): List<User> { val

    users = database.getUsers() return if (users.isNotEmpty()) { } else { } }
  31. Caching class ApiClient { suspend fun getUsers(): List<User> { val

    users = database.getUsers() return if (users.isNotEmpty()) { users } else { } }
  32. Caching class ApiClient { suspend fun getUsers(): List<User> { val

    users = database.getUsers() return if (users.isNotEmpty()) { users } else { httpClient.get().also { database.inserUsers(users) } } }
  33. kotlin { cocoapods { summary = “Shared Module" frameworkName =

    "shared_framework" } } Cocoapods Integration
  34. Kotlin Multiplatform Libraries • KaMPKit • Oolong - MVU for

    Kotlin Multiplatform • Reaktive - Kotlin Multiplatform Impl of Reactive 
 
 Extensions