https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
m

Maurice Jouvet

07/09/2020, 1:51 PM
Hi, I have started a new project with KMP. I already tested one successfully, but the architecture wasn't good enought for me. Concretly, I would like to call that easily on iOS:
// UseCase
suspend fun run(params: LoginModel): Token = authenticationRepo.auth(params)
It's easy on Android but on iOS I'm struggling.. I used to create a Protocol and a view that is the copy of the android version, but I have to work with event and callbacks. Is there an "easy way" to do the same android call that on iOS :
@UiThread
fun authenticateAsync(loginModel: LoginModel): Deferred<Token> {
return viewModelScope.async {
authenticationTokenUseCase.run(loginModel)
}
}
s

streetsofboston

07/09/2020, 1:53 PM
This will improve in newer version of KMP and Kotlin, but on iOS it will remain some form of callback. For our project we expose suspend funs and Flows by classes that take callbacks and handle lifecycle/scoping internally.
m

Maurice Jouvet

07/09/2020, 1:54 PM
Ah ok.. Do you have a good example? I would like to have a good architecture, with easy maintenability?
Anyway thank you for your quick response.
b

bsimmons

07/09/2020, 1:58 PM
This is the strategy that I've been using and it works well on iOS. (Check out the presentation layer section.) https://proandroiddev.com/clean-architecture-example-with-kotlin-multiplatform-c361bb283fd0 Basically, the view is passive and is controlled by a presenter. This allows for a natural use of coroutines and avoids callbacks et al.
s

streetsofboston

07/09/2020, 2:01 PM
We have most of our code in commonMain, from the ViewModels all the way down (at the lowest layers, we use GraphQL, etc, and a bunch of `actual`s to satisfy the `expect`s). The code that is Android (Kotlin) or iOS (Swift/Obj-C) is only the UI. The ViewModels expose observable properties for ui-data to be shown on the screen and for navigation-events. The ViewModel-properties are
Observable<T>
instances and
class Observable<T>
is of our own making. The
Observable
take a
viewModelScope
when created and receive the
CoroutineScope
from the UI (lifecycleObserver of Activity or Fragment) when observed. For iOS, for now, the
CoroutineScope
from the UI is just
null
and it will use the
viewModelScope
instead (ie ViewModel’s scope/lifecycle is the same as the scope of the iOS UI) The UI, in both Android and iOS, creates an instance of this
Observable
with a plain callback
(T) -> Unit
(iOS) or
suspend (T) -> Unit
(Android). The inner-workings of the
Observable
will call this callback when appropriate.
This means, as far as the UI is concerned, suspend fun and Flows from the ViewModel appear as plain callbacks wrapped inside that special
Observable
class
m

Maurice Jouvet

07/09/2020, 2:07 PM
Thanks to both of you. I'll dig into those solutions.
s

streetsofboston

07/09/2020, 2:10 PM
My setup is based on a MVVM type of UI-pattern for the app.
a

Arkadii Ivanov

07/09/2020, 4:49 PM
I always try to not expose any async API. It is better to handle everything in a KMP module and expose some sort of a facade with lifecycle methods. A UI can be defined as an interface and injected into the facade implementation.
Here is my article demonstrating one possible solution: https://badootech.badoo.com/mvi-in-kotlin-multiplatform-part-1-1-of-3-205c6feb4ac7
💯 1
s

streetsofboston

07/09/2020, 4:57 PM
^^^ That looks great, using MVI in KMP.
m

Maurice Jouvet

07/09/2020, 8:04 PM
Who nice as well. Thx a lot too.
9 Views