Slide 1

Slide 1 text

Meet Kotlin Multiplatform Mobile KMM for short Loveleen Kaur Senior Engineer (Astrotalk) Google Android Educator

Slide 2

Slide 2 text

Who am I? ● Loveleen Kaur ● Senior Engineer - Android @ Astrotalk ● Core Team Member @ Google Developer Groups Chandigarh ● Co-Organizer @ Kotlin Chandigarh User Group ● Android Educator @ Android Educators Community India ● Phd Research Scholar ● Technical Speaker ● Develop Mobile Applications ● Happy Android Developer :)

Slide 3

Slide 3 text

Questions I will try to answer -What is the difference between KMM and other multiplatform solutions like a flutter, react native, etc? -Is this a good solution for your business and why we thought it is a good decision for us? -How does iOS read the shared module? -How much code can we actually share? -What are the most important libraries and what these are doing? -Is KMM production ready? -Pros and cons of KMM

Slide 4

Slide 4 text

Cross-platform mobile framework popularity

Slide 5

Slide 5 text

Cross-platform mobile framework popularity

Slide 6

Slide 6 text

Google trends

Slide 7

Slide 7 text

Share code jvm Android iOS Linux macOS Windows JS watchOS tvOS

Slide 8

Slide 8 text

KMM First Multiplatform Kotlin 1.2 November 2017 Announced August 2020

Slide 9

Slide 9 text

Why we choose KMM • Small team • Business logic in one place • iOS needed refactor

Slide 10

Slide 10 text

KMM, the PoC • Configuration is tricky, but manageable • Things that works on android, do not need to work on iOS • One repo vs 3 repos • iOS simulator != iOS real device • Sample project != big project

Slide 11

Slide 11 text

Networking October 2021

Slide 12

Slide 12 text

January 2022 Networking Persistance Models

Slide 13

Slide 13 text

March 2022 Networking Persistance Models Repositories UseCases

Slide 14

Slide 14 text

June/July 2022 Networking Persistance Models Repositories UseCases View Models UI layer

Slide 15

Slide 15 text

Share code Domain Repositories Persistance Networking ViewModels Presentation Business(Kotlin) Framework(iOS, Android)

Slide 16

Slide 16 text

KMM libraries 137 libraries KTOR KOIN SQLdelight Multiplatform settings kotlinx.serialization kotlinx.datetime BuildKonfig Moko-resources

Slide 17

Slide 17 text

Networking with KTOR • open-source • lightweight • powered by coroutines • Build by JetBrains

Slide 18

Slide 18 text

Networking with KTOR fun createHttpClient(httpClientEngine: HttpClientEngine, logger: Logger) = HttpClient(httpClientEngine) { defaultRequest { url.protocol = URLProtocol.HTTPS url.host = BuildKonfig.BASE_URL parameter("apikey", BuildKonfig.API_KEY) parameter("Accept-Language", languageCode ?: "en") } install(ContentNegotiation) { json(json) } install(Logging) { this.logger = logger level = logLevel } }

Slide 19

Slide 19 text

Networking with KTOR fun createHttpClient(httpClientEngine: HttpClientEngine, logger: Logger) = HttpClient(httpClientEngine) { defaultRequest { url.protocol = URLProtocol.HTTPS url.host = BuildKonfig.BASE_URL parameter("apikey", BuildKonfig.API_KEY) parameter("Accept-Language", languageCode ?: "en") } install(ContentNegotiation) { json(json) } install(Logging) { this.logger = logger level = logLevel } } OkHttp + Retrofit Retrofit.Builder().baseUrl() In interceptor: chain.request().header()

Slide 20

Slide 20 text

fun createHttpClient(httpClientEngine: HttpClientEngine, logger: Logger) = HttpClient(httpClientEngine) { defaultRequest { url.protocol = URLProtocol.HTTPS url.host = BuildKonfig.BASE_URL parameter("apikey", BuildKonfig.API_KEY) parameter("Accept-Language", languageCode ?: "en") } install(ContentNegotiation) { json(json) } install(Logging) { this.logger = logger level = logLevel } } OkHttp + Retrofit Retrofit.Builder().baseUrl( ) In interceptor: chain.request().header( ) .addConverterFactory(jsonConverter) Networking with KTOR

Slide 21

Slide 21 text

fun createHttpClient(httpClientEngine: HttpClientEngine, logger: Logger) = HttpClient(httpClientEngine) { defaultRequest { url.protocol = URLProtocol.HTTPS url.host = BuildKonfig.BASE_URL parameter("apikey", BuildKonfig.API_KEY) parameter("Accept-Language", languageCode ?: "en") } install(ContentNegotiation) { json(json) } install(Logging) { this.logger = logger level = logLevel } } OkHttp + Retrofit Retrofit.Builder().baseUrl( ) In interceptor: chain.request().header( ) .addConverterFactory(jsonConverter) .addInterceptor(httpLoggingInterceptor) Networking with KTOR

Slide 22

Slide 22 text

Http Client Engine Android.create() val logger = object : Logger { override fun log(message: String) { Log.i(tag, message) } } Darwin.create() Logger.DEFAULT Logger Networking with KTOR

Slide 23

Slide 23 text

Actual/Expected

Slide 24

Slide 24 text

Actual/Expected //common expect val httpEngine: HttpClientEngine expect val logger: Logger //androidMain actual val httpEngine = Android.create() actual val logger = object : Logger { override fun log(message: String) { Log.i(tag, message) } } //iosMain actual val httpEngine = Darwin.create() actual val logger = Logger.DEFAULT

Slide 25

Slide 25 text

iOS and coroutines

Slide 26

Slide 26 text

iOS and coroutines Async/Await RxSwift Combine Callbacks

Slide 27

Slide 27 text

iOS Source: https://dev.to/touchlab/kotlin-coroutines-and-swift-revisited-j5h func createPublisher(flowAdapter: FlowAdapter) -> AnyPublisher { return Deferred>> { let subject = PassthroughSubject() let job = flowAdapter.subscribe( onEvent: { (item) in let _ = subject.send(item) }, onError: { (error) in subject.send(completion: .failure(KotlinError(error))) }, onComplete: { subject.send(completion: .finished) } ) return subject.handleEvents(receiveCancel: { job.cancel(cause: nil) }) }.eraseToAnyPublisher() }

Slide 28

Slide 28 text

Shared iOS class FlowAdapter( private val scope: CoroutineScope, private val flow: Flow ) { fun subscribe( onEvent: (T) -> Unit, onError: (Throwable) -> Unit, onComplete: () -> Unit ): Job = flow .onEach { onEvent(it) } .catch { onError(it) } .onCompletion { onComplete() } .launchIn(scope) }

Slide 29

Slide 29 text

SSOT for resources

Slide 30

Slide 30 text

Resources Moko-resources https://github.com/icerockdev/moko-resources

Slide 31

Slide 31 text

Strings.xml Resources Cancel Current location Yesterday

Slide 32

Slide 32 text

Compose Resources stringResource(id = SharedRes.strings.my_string.resourceId) Swift/SwiftUI let string = MR.strings().my_string.desc().localized() LocalizedStringKey(MR.strings().email.resourceId)

Slide 33

Slide 33 text

Resources Common val stringDesc = StringDesc.Resource(SharedRes.strings.airlypedia_title)

Slide 34

Slide 34 text

Resources Common val stringDesc = StringDesc.Resource(SharedRes.strings.airlypedia_title) .toString(context)

Slide 35

Slide 35 text

Resources Common val stringDesc = StringDesc.Resource(SharedRes.strings.airlypedia_title) .toString(context) .localized()

Slide 36

Slide 36 text

Resources Common val stringDesc = StringDesc.Resource(SharedRes.strings.airlypedia_title) expect fun ResourceStringDesc.getText(): String

Slide 37

Slide 37 text

Resources Common val stringDesc = StringDesc.Resource(SharedRes.strings.airlypedia_title) expect fun ResourceStringDesc.getText(): String actual fun ResourceStringDesc.getText(): String = this.toString(appContext)

Slide 38

Slide 38 text

Resources Common val stringDesc = StringDesc.Resource(SharedRes.strings.airlypedia_title) expect fun ResourceStringDesc.getText(): String actual fun ResourceStringDesc.getText(): String = this.toString(appContext) actual fun ResourceStringDesc.getText(): String = this.localized()

Slide 39

Slide 39 text

How to read KMM in platforms?

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

dependencies { implementation(project(":shared")) }

Slide 42

Slide 42 text

dependencies { implementation(project(":shared")) }

Slide 43

Slide 43 text

dependencies { implementation(project(":shared")) } New Run Script Phase

Slide 44

Slide 44 text

dependencies { implementation(project(":shared")) } New Run Script Phase https://kotlinlang.org/docs

Slide 45

Slide 45 text

Next steps • Use async/await in iOS for suspend functions • Try crashlytics, analytics, etc • Use KMM for web app • Share more assets

Slide 46

Slide 46 text

iOS & Android everyday

Slide 47

Slide 47 text

iOS & Android using KMM

Slide 48

Slide 48 text

Is it ready for production?

Slide 49

Slide 49 text

KMM - Pros and Cons • 100% Native • Android developers know Kotlin and Gradle • Optional • Still in Alpha

Slide 50

Slide 50 text

KMM - Pros and Cons • 100% Native • Android developers know Kotlin and Gradle • Optional • Still in Alpha • UI written separately

Slide 51

Slide 51 text

Meet Kotlin Multiplatform Mobile Thanks for listening! Loveleen Kaur Senior Engineer (Astrotalk) Google Android Educator