MVP in Kotlin Multiplatform
My colleagues and I have been experimenting with creating a cross-platform application with Kotlin Multiplatform. I’m excited to share with you on how to write a mobile application with Kotlin Multiplatform using the MVP pattern.
Kotlin and Kotlin Multiplatform
Kotlin Multiplatform is currently an experimental feature of Kotlin and thus you can expect it to be rough around the edges. Do not worry though, because The updates and bug fixes are active and frequent, and many third-party libraries are popping up like mushrooms after the rain. Here is a list of useful Kotlin Multiplatform libraries that can be used across platforms:
- SQLDelight — Database
- Ktor — Networking
- Kissme — Secure Key-Value store
- Multiplatform Settings — Key-Value store
- Klock — Time/Date
- kotlinx.serialization — Serialization
And many more! I’m looking forward to an upcoming feature of Kroto-plus which allows the generation and usage of Protocol Buffers and gRPC on Kotlin Multiplatform.
There are limitations that we need to take note, however.
- As mentioned, it is still an experimental feature of Kotlin. Things are not expected to be smooth, yet. The setting up of the project with IntelliJ and Gradle is still quite buggy and not set in stone yet.
- IDE support works great IntelliJ. But debug support of Kotlin Native code will have to be done on CLion, another IDE developed by JetBrains.
- The code sharing part of Kotlin Multiplatform is called the “common” in the project. It cannot contain platform specific code. But it can be easily circumvented by using the actual/expect feature of Kotlin Multiplatform which allows the common code to use platform-specific APIs.
- Kotlin Multiplatform is not for sharing UI code. But there are attempts that do exactly this.
The project architecture that I am going to implement with Kotlin Multiplatform is the Model-View-Presenter (MVP). The Model class, View and Presenter interfaces will reside in common directory while the code that implements the View interfaces will reside in the platform-specific directories.
- Create a Kotlin Multiplatform project with IntelliJ IDE. ➕ Create New Project → Kotlin → Kotlin (Mobile Android/iOS)
2. Use the default Gradle wrapper settings.
3. Choose a suitable project name. In our case we choose kotlin_multi_mvp_tutorial. Click NEXT and the Gradle will proceed to setup the project and download all the necessary dependencies. It will take quite a while depending on your internet connection speed.
Error! You might encounter this error message similar to below.
Please fix the ‘sdk.dir’ property in the local.properties file.
Normally Android Studio and IntelliJ will populate this sdk.dir variable in the local.properties file during the creation of Android project. But it seems like Kotlin Multiplatform is not doing this for us yet. If we look at the local.properties file in the project. This will be shown.
In my case, it is /Users/my_user/Library/Android/sdk. Refresh Gradle again and wait for it to run all the required steps to setup the project.
In the common code, define the interface. In this example, We will create a LoginView and LoginPresenter Interface in the commonMain directory as shown below.
4. We will create a User data class as our Model.
5. Implement the LoginPresenter interface in LoginPresenterImpl.kt.
And that’s it, we implemented a Presenter that can be used by both Android and iOS. Now we have to implement the view in each individual platform.
Since IntelliJ supports Android projects, we create our applications without leaving our IDE. First we’ll create an Android LoginActivity.kt in our main folder that will implement our LoginView interface defined in the common. We will declare and initialize the LoginPresenterImpl that we created in common.
Now that we are done on the Android side. Now let’s move on to implement this in iOS.
It will be a little rough to get started with the iOS project (Hence the reason Kotlin Multiplatform is still not production ready yet as the time that I’m writing this article). We will need to do the following in order to get started.
- Create a Gradle Wrapper with ./gradlew wrapper. The reason for this is for XCode to run the copyFramework task during Building Phase of the framework.
- Modify build.gradle so that copyFramework task will work. The code is shown below.
Afterward, implement LoginView on the ViewController class in ViewController.swift. declare and initialize the LoginPresenterImpl that we created in common like what we did for Android. Next, we will write our code as shown below.
Now we implemented the View and the Presenter. Let's run them on the simulators.
Thanks for reading! You can find the code to the repository here. And a huge thanks to Ho, Jon, and Toru for helping me out with the drafting of this post.