At our xDesign company innovation day a few months ago, the Android team wanted to spend time looking at Kotlin multiplatform and how we might leverage that in our future projects. As a team, we had adopted Kotlin early on and have written all of our Android projects since in Kotlin. A natural evolution of this is to look at how we can use multiplatform Kotlin for shared components in iOS and Android applications.
In an agency environment like xDesign, we are often asked to write apps on both iOS and Android simultaneously. They often interact with the same backend web server, meaning we write code to retrieve and parse data from external sources, sometimes combining data from different sources - for example we might need to get a car registration associated with a user from one web server, and then query the government’s DVLA website to find out what kind of car it is. Often, we need our applications to work offline, which involves storing data in a database, and retrieving that data if there is no connection. All of this is written separately for each platform (i.e. when developing for mobile, we write it twice). Our goal when exploring multiplatform Kotlin is to write these specific aspects once and re-use them across both iOS and Android.
Using the above frameworks, we are able to reduce the amount of code we have to write twice, but there are a number of drawbacks
- The ecosystem for the framework varies between platforms, but there are a lack of 3rd party libraries that are available in ‘native’ development - that is, developing in java or Kotlin for Android, and swift or objective-C for iOS. One example we have encountered recently was trying to use a calendar library in our flutter project. In a native iOS or Android project we would have an abundance of options, whereas in flutter we found only one - which did not have all of the features we needed.
- Writing operating specific code is sometimes disproportionately complicated - for example, dart ‘channels’ in flutter development are a way of flutter interacting with specific android features. However, the time to write these channels often make the time saved in writing cross platform code redundant.
- You have to commit to one of these solutions - despite the best efforts of each of the different frameworks, if you have chosen to use, e.g. react native, for your development and then decide half way through a project that something is not going to be possible, it’s too late. The time taken to re-work your features makes it infeasible, especially in an environment with tight deadlines, impossible.
Why Kotlin Multiplatform is Different
The intention of multiplatform kotlin is not to replace an iOS developer with a kotlin developer, but to reduce the amount of work they need to do. Whereas a native iOS swift developer really has no role in a react native project, our intention is for iOS developers to develop an iOS app - but with a great deal of the work already done.
If we were to think about our applications and their architecture it might be described like this:
With multiplatform Kotlin, our intention is for the top layer to be written in swift and iOS specific components, but using multi platform code to store, retrieve and convert data. In this way, an iOS app will look and feel native but will have a portion of its code written in kotlin.
To contrast with the previous drawbacks of entirely crossplatform development, kotlin multiplatform offers us the following:
- By default, you would write your code natively (in iOS swift or objective-C, in Android java or kotlin) and from your native code, you have the option to import and use libraries written in kotlin from your native code. As a result, the ecosystem is as rich as native development - which means that in all cases, you can use native libraries and the official support libraries. In addition, any breaking changes in the operating systems are less likely because Google / Apple have a stake in not breaking them for the languages they support and maintain
- Platform specific code is as easy as native development, as that is what your project is setup to do
- You can stop using kotlin multiplatform whenever it stops suiting you, without having to re-write your code. If something is impossible to do in a multiplatform way, just revert to writing it in each language, or write that code in your language. In fact, because 99% of the code is going to be in kotlin, which is what our Android apps are written in anyway, there’s very little downside to writing our Android code (albeit in a specific way) and only using specific parts in iOS that we know will work, since if we reach a point where the kotlin code does not work on iOS anymore - it is still a first class language on Android, and your time writing it will not have been wasted.
The basic process that we intend to follow to try a transition to multiplatform kotlin is as follows:
- Find appropriate multiplatform libraries that would allow us to share the code we use for backend and data storage - we would use our bi-weekly innovation days in order to do this
- Identify a project where there will be both an Android and an iOS application with similar requirements. We will then develop the Android part of this project in such a way as to allow the code to be compiled to iOS later on - i.e. by using the libraries from the innovation day
- If development of the project was not hindered by using this approach, at or near the end try and move the completed iOS application’s UI to make use of the libraries that we developed for Android. In this way we will be sure that multiplatform kotlin is an effective solution to a real-world project for both iOS and Android, where a one or half day experiment can often lead to finding issues much later on in development which unforeseeable limitations hindering development.
Exploring The Libraries
Our first step was to identify libraries that would replace our well worn Android libraries for backend and data storage. Recently, we have made use of ‘Room’ which is an Android specific data storage library. Our preferred solution to replace this with a multiplatform alternative is sqldelight:
Our second library choice was to replace a well known library called retrofit. For this we opted to use ktor:
Whilst a number of options exist for making web requests, we decided to use ktor as it is developed and maintained by intellij - the company which created kotlin - and there is therefore a good chance that it continues to be supported for a long time to come.
Our innovation day threw up a number of other challenges which we overcame with different solutions. One is that we rely on most projects on a native ‘date’ library, and we were forced to find an alternative for that. Another was to do with serialization - i.e. the process of taking json and converting it into a format that we can use in code. Again, we were able to use a solution provided for us by jetbrains.
With all this complete, we are ready to start the next phase - developing an Android project using these libraries.