Smooth transition from Android and JVM to KMP: a three-year journey

Emad Razavi
8 min readApr 11, 2024

--

In this article, I am trying to describe the path of the project that we expanded after three years and finally became KMP. One of my reasons for publishing this relatively long article is that if you find yourself programming in part of this path, you can gain a better understanding to continue the path of your project. Due to some necessary considerations, I am not able to provide real examples (and describe the business of the project). But I try not to hinder the clarity of my technical explanations. This writing is based on my experiences, I may have made mistakes in writing small parts of it. I hope you will improve this text with your constructive feedback.

May 2019
At the beginning of my collaboration, three Android projects, which were not in the right architectural condition, were built to meet the needs of the company, which all had a lot in common from a business point of view (for example, the database was all very similar). My first step when entering the company was to use Build Variants. With this, many bugs appeared and led to many file changes, but finally all three projects reached moderate stability. The development has expanded, we have improved the appearance of the improvement program. We migrated from Volley to Retrofit. At this time, our project did not yet have DI(Dependency Injection). All program sources were implemented with Java and all program appearance was implemented with XML. There were no tests written in the program and we had created Java modules for some business needs. For example, the common module which included the application utilities.

February 2020
We went a little further. The project had moved forward with the implementation of extensive business segments. I tried to convert the project to Single Activity. We went to Fragment and Navigation Component. A little later, we moved part of the Custom Views related to the project to a separate Android module. Our goal was to introduce the designed Design System into the project as soon as possible. A goal that was not realized until the deployment of Jetpack Compose and its replacement with XML.

May 2020
The first Kotlin code was added to the project. From this time, new files were created mainly with Kotlin, and old Java files were gradually converted to Kotlin. Sometimes there were bugs in this conversion, but we couldn’t avoid it. Especially because the project still did not have the correct structure in terms of architecture and almost no tests were written for any of the project’s parts.

March 2021
We have been informed that we are going to have a JVM version of this project for Linux operating system. With the addition of Mr. Mohammad Sohrabi to the project, the focus on the architectural discussion of the project increases. Finally, the project architecture reached its current form, i.e. Clean Architecture + MVVM + DI. Focusing more on the architectural aspects of the project, significant classes, folders, and modules were gradually created, modified, or removed. Converting Java files to Kotlin was also speeded up. Kotlin Coroutines came into play. Also, Hilt Dependency Injection was added to the project.

August 2021
After parts of the Android project were implemented in Abstraction/Implementation form, it was time to build a JVM project. At this time, we had implemented the database connection in our Android project with Room (which, as of this writing, does not support other platforms) and we chose the Exposed library for the JVM. This library did not support Android. A better option was SQLDelight, which supported our target platforms well. We were not aware of this at the time. For Dependency Injection in Android we used Hilt which was not supported in JVM. In JVM we went for Dagger. To communicate with the server, we went to the powerful Ktor library because Retrofit could not be used on a platform other than Android. In order to be able to use common modules between two projects, we went to Maven Publish and Gitlab Package Registry. A little further, for example, a module was formed for all communication with the server based on Ktor, so that there is no need to write each part of these codes separately. For Logging, we went to SLF4J based libraries. On the JVM side, we used Log4j and on the Android side, we started migrating to Logback.

December 2021
We added a talented member to the team. Mr. Mehdi Bahmanpour, with his artistic spirit and a great understanding of programming, gave us the hope that we can expect very attractive works in terms of the appearance of the program. During this time we made many changes on the application domain and on the JVM side, we deployed the Picocli library to improve the CLI user interface. On the database side, with the new understanding we gained from the Exposed library, we made improvements to our implementations and the way we wrote our queries. Mehdi took the initiative in implementing some parts related to Gradle. For example, creating a script to specify the Debug and Release version in the JVM project or converting all Groovy files to Kotlin (kts format).

July 2022
Little by little, the project stabilizes in terms of business, and we were able to find more time and focus for technical tasks. Finally, the first codes of Jetpack Compose were added to the project by Mehdi. Business was led by Mohammad and UI codes was led by Mehdi. I was also in charge of the overall management of the project and I tried to keep the idea of converting projects to KMP always alive in the minds of other members of the team.

November 2022
We moved the project to Version Catalog. A change that made it easier for us to make other changes to Gradle.

April 2023
At this time, we came to the conclusion that it’s time to say goodbye to the powerful Room library and migrate to SQLDelight on both Android and JVM. In order to make this change with minimal issues, Mohammad started a mission to write tests in the data layer (especially the Datasource layer). With his test writing process finished, he and I got busy writing sq files (for SQLDelight) and implementing other changes. After some time, due to the differences between Dagger and Hilt, as well as the differences between the SQLDelight drivers, it was found that there was a need for changes in the way tests were run and code changes in that section. All in all, this code migration took us considerable time due to the paradigm difference between Room and SQLDelight. But then, for both Android and JVM projects, we had a common module to communicate with the application’s database.

June 2023
Mehdi became responsible for the follow-up of the task, which we mistakenly called Feature Flag at that time. The purpose of this task was to identify common features in the business layer of each of the three build flavors that we had for the Android project, instead of considering a specific mode based on the flavor, which can be changed in a certain place by changing each of them. (eg a file referenced in build.gradle), we can apply a new feature to that Flavor. For this change, it was necessary for Mehdi to separate the different parts of the program in terms of features and have appropriate implementations for each combination of situations that may occur. This work finally led to the ability to control more features of each flavor of the Android application. The presence or absence of any of the defined features became a Use Case. It took the business focus out of Flavor and gave us more flexibility to develop projects for different companies with new business conditions.

July 2023
A fourth flavor has been added to the Android project. Before that, it was necessary to divide a Feature into two Features. Due to the previous implementation, the time to add this Flavor and get its proper output was very short. A little while ago, we sadly said goodbye to Mohammad, and some time later, with the addition of Mr. Mohsen Abedini, we hoped to continue our previous path. The way we can use Mohsen’s high attention to detail capacity, studying documentation in detail and his keen interest in understanding the latest developments happening in the Android world.

March 2024
We went to the final step. At first we thought that KSP wouldn’t work properly with Build Flavors and we would have to spend a significant amount of time implementing anything else. Also, we had another misconception and that was that if the Android project is implemented with Hilt, it is not possible to use it in the Android module and it must be converted to another library. For this assumption, We went to Kotlin Inject and converted the JVM project from Dagger to Kotlin Inject. Mohsen went to the Android project and followed up on that conversion. However, this conversion (which we didn’t need to do at the moment) allowed us to share more of the projects in DI. At the same time, all Java/Kotlin modules and then all Android libraries were transferred to the JVM project.

Finally, the structure of the KSP project was formed with the addition of a Kotlin Multiplatform module named shared, and the dependency was given to the JVM project. For the Android project, the platform-specific dependency was not defined in the shared module, and the Android project was only dependent on the common part of this module. By running the project on each of the two platforms, we were relieved to finally have a KMP project, however minor, that we should try to improve.

Final remarks
1. From the beginning, our main technical goal was to unify the projects. But most of the development time was spent on improving the business needs. When maybe if we had reached this technical goal a little earlier, we would have faced less waste of time. Considering the stability of KMP, I think now is the best time to merge the projects.
2. The Room project team is developing tasks to be released as a KMP library.
3. You can find me, Mohammad Sohrabi, Mehdi Bahmanpour and finally Mohsen Abedini on LinkedIn.
4. I have set up a number of free half-hour sessions on ADPList every Thursday for which you can make an appointment if needed.

--

--