One of the main concerns in mobile development is to develop the same application twice (for Android and iOS), although they share the same features. At some point in mobile history, it was even worse: iOS, Android, WindowsPhone and Blackberry.
Over the years, many companies and communities have tried to alleviate this problem with different tools/frameworks. The long-awaited Holy Grail of cross-platform development is an idea that is old and simple, Write once, run anywhere (WORA).
After many years searching for this, it looks like we now have some options that make cross-platform feasible, and they are not just another promise of the Holy Grail.
In this post we are going to give you a broad view of crossplatform options, and a deeper look into Kotlin Multiplatform from a technical and an organizational perspective.
Crossplatform benefits and downsides
The promised WORA approach using crossplatform tools is not all about benefits, you can also expect many downsides, and usually these downsides are negleted under the cost reduction promise. The obvious benefits are:
- Lower cost than native.
- Needing only one engineering team for both platforms.
- Consistency between both platforms, no longer need to worry about the two apps working differently.
- Reusing source code between the two platforms, and maybe also the web.
Some downsides to be aware of are:
- They add another layer on top of iOS and Android and therefore another point of failure to check when there is a bug that only occurs in one of the platforms
- You may still need to develop part of the app in native, so you may need three different profiles instead of just one (the crossplatform developers, but also Android and iOS developers)
- New features of the native SDKs will not be available as soon as they are released, you must wait until they are added to the tool
- Crossplatform will never achieve the same performance and flexibility of native apps, you will always be limited by the tool.
- You must develop a generic or agnostic UX-UI for both platforms that may feel alien compared to the native usage and appearance of the device.
A little bit of history
As soon as iOS and Android started to gain popularity, plenty of initiatives appeared to try to achieve the magic WORA. Most of them were quickly adopted with enthusiasm by the community and also quickly abandoned to adopt the next promising tool hoping to get a less disappointing result. Some of them still have their believers supporting them, others were acquired by big companies and were diluted in a bigger software solution and many others have been recently created from scratch but with low adoption. Some examples of all of them are:
Discontinued or being discontinued in the short term
|Appcelerator Titanium||Acquired by Axway in 2016 and will be discontinued in 2022.|
|Marmalade||Discontinued in 2018.|
|PhoneGap||It was acquired by Adobe in 2011 and discontinued in 2020.|
|Sybase Unwired Platform||Acquired by SAP in 2010 to be diluted in SAP Mobile Platform and replaced in 2020 by SAP Cloud Platform Mobile Service.|
|Syclo||Acquired by SAP in 2012, diluted in SAP Mobile Platform and discontinued in 2015.|
Diluted in a bigger company and forgotten
|AppGyver||Another low code platform. Acquired by SAP in 2021.|
|FreedHenry||Acquired by RedHat in 2015.|
|Kony||Another low code platform. Now is part of Temenos suites (acquired in 2020)|
|Service2Media||Acquired by CM.com in 2016.|
|Xamarin||Acquired by Microsoft in 2016 and diluted on MAUI (Multiform App User Interface) in 2021|
Still alive but with low or moderated adoption
|Apache Cordova||Opensource fork of PhoneGap. It is still alive and used by several developers.|
|Capacitor||An open source native runtime for building Web Native apps. The new alternative to Cordova by IONIC team.|
|Go Mobile||It generates bindings from a Go package and invokes them on Android or iOS.|
|IONIC||A set of Web Components emulating mobile native interfaces, allowing the user to choose any user interface framework, such as Angular, React or Vue.js, usually used with Cordova.|
|J2ObjC||An open source command-line tool from Google that translates Java source code to Objective-C for the iOS (iPhone/iPad) platform.|
|PowerApps||Another low code platform. The Microsoft alternative for low code.|
|Progressive Web Apps||A marketing term coined and promoted by Google defining a set of existing techniques to imitate native apps from a mobile web. Apple also coined its own name for this: “HTML5 apps”. Apple’s lack of enthusiasm has driven PWA to a low adoption.|
|RhoMobile||Acquired by Motorola Solutions in 2011, then acquired by Zebra Technologies in 2014, opensourced and maintained by Tau Technologies since 2016.|
|Shared C++ libraries||Just using C++ to compile low level code|
And many others…
Leading platforms: Facebook and Google pushing their own solutions
After many years, it looks like we now have a couple of crossplatforms tools, Flutter and React Native, that are being broadly adopted by the industry with good results.
These tools have been developed by Facebook (React Native) and Google (Flutter) and both companies are using them successfully for their own developments. Many other companies have also adopted them successfully.
Flutter (Google): Flutter follows a new approach. It is neither a transpilation tool nor a web page wrapper. Flutter uses a C++ library to draw the UI on top of a canvas, achieving the same performance as native apps, which is something similar to game development. It also offers a fast way to develop UIs using widgets, as programming language Flutter uses Dart.
In the following graphic you can see how the interest on IONIC and Apache Cordova decreased while React Native increased. Around March 2020, the interest on Flutter surpassed ReactNative according to Google Trends
Kotlin Multiplatform: not just another cross-platform tool, but a real native development enhancement
There is another recent alternative to these crossplatform tools: Kotlin Multiplatform. We have been using it during the last year and we (and our clients) are very happy with the results.
This new approach with Kotlin Multiplatform tries to leverage the PROs of the crossplatform and to reduce or eliminate the downsides, so there is not yet a winner in the WORA race!!
Kotlin is a programming language created by Jetbrains in 2012. One of its advantages is that it is 100% interoperable with Java; it contributed to its meteoric growth. Moreover, in 2017, Google added official support for Kotlin in Android development and Jetbrains announced Kotlin Multiplatform.
We do not consider Kotlin Multiplatform another cross-platform tool, we consider it an enhancement to native development.
How it works
The idea is very simple. If we can compile Kotlin to be used for Android, why not take advantage of this code for iOS? The Jetbrains team started working on the possibility that Kotlin could also be compiled for the iOS virtual machine (LLVM). This way, we would have a 100% native code, without wrappers, canvas or web pages. Everything would be integrated into the system and there would be no barriers to connect with specific features of each platform.
What does this diagram mean? It means that Kotlin source code is compiled directly for each archictecture. The Kotlin compiler uses LLVM to translate the kotlin code into a native one, with just the instruction set needed for the concrete architecture, for example iOS x64 ARM.
This approach has an inconvenience that could be considered a disadvantage: we will still have to develop the UI layer twice. Although it may be considered a disadvantages because the extra cost, in some cases it could be an advantage, as you can develop a slightly different UI for each platform giving the user an experience near to the standard usage of each platform. As we will see in the “What is coming next” section, there is a new alternative to develop the UI (Jetpack Compose) that could alleviate this inconvenience.
Following this approach we will develop the common parts as shared libraries or modules. In the case of Android we can generate an aar/jar file, and in the case of iOS we can generate a .framework that can be used in Cocoapods or Swift package manager.
With this approach, the compiler will generate the library with only the code related to it, which means that in case of iOS, the .framework will include the shared code and the platform specific code (iOS code but written in Kotlin)
This libraries or modules will be used by the native UI layer, but being a native library, there is no constraint on how to use them, so they could also be used from a plugin for Flutter, a connector for React Native or Xamarin, or even connect it with a Cordova web plugin. Obviously, although technically possible, there is not much business benefit on using such combinations.
Adopting the right solution is not only about choosing a programming language or a tool, there are plenty of implications beyond it. One of them is adopting the right architecture you will use on top of the tool or language.
Our choice of Kotlin Multiplaform was accompanied by an architectural implementation shared between both platforms.
You can find plenty of references on the Internet about architectural decisions for mobile apps based on Clean architecture, SOLID principles and Google recommendations, whicha are concepts that must be part of any modern architecture. Below you can find our proposal of this architecture for Kotlin Multiplatform apps.
This architecture can be used for both platforms, as it clearly identifies the common parts, the interfaces defining abstractions, as well as the parts that are tied to each platform and cannot be shared.
As you can see, the UI is implemented two times, but… is it a problem? In our opinion, no. You can expect iOS users to be used to Cupertino guidelines, while Android users will be used to Material Design.
We prefer to give the best experience to the user. For example, Android users are familiar with Google Maps, but iOS users like to use Apple Maps. With Kotlin Multiplatform there is no code such as:
if (platform is iOS) then AppleMaps else GoogleMaps.
With Kotlin Multiplatform you just need to implement the common interface, and that’s it.
You can find an opensource implementation example of this architecture in our Github repository
Not everithing is about technology; adopting Kotlin Multiplatform as our preferred tool also created some organizational challenges. One of the main drawbacks of native development is that you must have two different teams, one for Android and one for iOS. This organization can lead you to have silos for each platform, where each team has its own architecture and its own isolated technical decisions.
You can expect some efforts from the Product Owners/Scrum Masters to assure alignment on both teams, and even with that, it is quite usual to have different results because the apps may behave differently.
This organization may have made sense when development was done with Java and Objective-C, which are syntactically very different languages, but Kotlin and Swift are closer and nowadays even some architecture patterns are similar in both platforms. On top of that, if you use Kotlin Multiplatform to develop common parts, you can expect the iOS team workload to decrease.
For this reason, we decided to unite our iOS and Android teams under a Native App team. We still have specialized architects for iOS and Android but under a T-shaped organization where the whole team is proficient in both platforms and has a deep expertise in one of them.
Each feature is developed end-to-end by a developer on both platforms, where they program and test the business logic in Kotlin Multiplatform as well as the UI for iOS and Android. When it comes to peer review, at least one reviewer must be specialist in the platform.
A single developer will be accountable and responsible for the result on both platforms, so there is no further need to align efforts between teams.
Furthermore, the team is very motivated to grow their area of expertise, because they became a specialist on native apps, and not only on a technical silo.
What is coming next: further enhancements to Kotlin Multiplatform approach
In the coming years we will keep a close eye on Jetpack compose, which it is supposed to become compatible with iOS in the near future. If this initiative succeeds, the main drawback of Kotlin multiplatform (develop the UI both times) will be mitigated by this library, because potentially, you will be able to reuse the UI development in both platform.
But there is another player that could help us to deploy the UIs faster than we do now: SwiftUI.
SwiftUI is the new way of declaring UIs on iOS, and yes, declaring is the right word. Because it’s so declarative, let’s look at the difference developing the UI with Compose and SwiftUI. As you can see, the code is so similar, so it’s easy for iOS developers to understand Compose and vice-versa.
Dismantling a fake assumption about cost
One of the drawbacks of native development is having a higher cost because you must developed it for two platforms, which usually leads to a false assumption that it will cost twice as much.
Let us make a simulation with an imaginary project estimated in 1.000 person/day to develop an Android app (without iOS). A standard share of effort among profiles could be something like this:
Now imagine you have to develop it for both platforms (iOS and Android ) and you decide to use the Native SDKs. You can expect to increase effort on all profiles.
You will need twice the effort for developers, the Scrum Master will need more time because there are more people on the team, Product Owner and UX/Design team will need more effort for the specificities of the iOS, and finally the testing team will need to test it in both platforms with real devices, although you can reuse the test plan. With all these assumptions you would get these figures:
Now let’s suppose you chose one of the most used crossplatforms tools as Flutter or React Native instead of Native SDKs. In this case, you would only need some minor development adjustments on each platform.
Let’s assume it could be an additional 20% for iOS respect the single version an additional 65% for testing because you still have to test it twice on real devices.
And finally, let’s simulate the Kotlin Multiplatform option. In this case, if we assume that 50% of the work is UI, we will need 750 person/day instead of the initial 500 person/day, 65% of additional tests for the second platform (same as crossplatform) and as we want to get the best UX of each platform, we can also assume an optional 40% of additional effort in UX design for this reason.
Putting it all together we get the following figures:
According to this simulation, if you analyze all the costs involved developing an application for two platforms, the difference between a crossplatform and native is substantial, but if you compare crossplatform with Kotlin Multiplatform, the difference is not too much.
Is it worth it to assume all drawbacks of cross-platform are only for a small savings?.
That will depend on your business case and the type of app that you want, but for sure, the decision must be made knowing that the cost of the Native option using Kotlin Multiplatform is far away than twice the cost of a crossplatform tool.
Success case: Eroski – Caprabo Apps
We started to develop The Eroski app in 2014. Most of the code was on Java and Objective-C and after several years the app had some technical debt to be repaid.
The client decided to invest in a redesign and we took the opportunity to migrate from legacy Java and Objective-C to Kotlin Multiplatform, and then migrate step-by-step each one of 50 legacy screens without blocking the updates of the app during the redesign.
The first step was to invest some effort on spikes to demonstrate the technical feasibility, and the second step was to invest in the team to be technically proficient in both platforms. Then we started the migration to Kotlin Multiplatform and the development of 20% of the screens before the first release. Afterwards we continued with the rest of the screens and new features.
Being 100% interoperable with Java, Swift and Objective C, we can seamlessly connect our Kotlin code with our legacy code, thus developing a smooth migration.
The project was finalized on time, and at a high-quality level with more than 99% crash-free users with around 800k active users
Summary & conclusions
At this moment we have several options to achieve the beloved WORA, React Native, Flutter and Kotlin Multiplatform beeing the most promising.
According to the Gartner “Hype Cycle for Application Architecture and Development, 2020” one of the variables you must consider when to choosing a the cross-platform tool is the availability of those skills in your company.
“Inventory the existing development skills of the organization’s in-house development team and choose the native cross-platform development tool that best extends those skill sets.”
If you have a web development department using React, mobile is not at your core business, it is just a sanity feature, and you do not have a clear vision to develop “best-in-class” apps. You may perfectly achieve your goals with React Native so there is no need to create a specialized team to develop apps.
At Worldline Mobile Competence Center we have the skills to develop native apps and we want to deliver best-in-class apps at competitive cost, so our choice is Kotlin Multiplatform. Kotlin Multiplatform has all the benefits and excellence of native development and at same time can compete in price and “time to market” with any crossplatform tool.
And what about Flutter?
We do not consider Futter and alternative to Kotlin Multiplatform, we consider it complementary. Flutter will be our choice when there is no need for complex architectures and when you have a common and complex UI.