Why we are not cross-platform developers

Since the invention of the smartphone many developers have asked the same question: how can I build and release an app for multiple platforms? Where at first there were iPhones and BlackBerries, Android joined, Windows Phone made a brief appearance, and all along web has been part of the discussion. Releasing your app for each and every platform sounds expensive— surely there must be a solution that cuts the cost of developing multiple apps, right?

Here at Pixplicity, where we’ve been making apps for over six years, things are no different: though we started out exclusively as native Android developers before we offered full-spectrum solutions, over the years we’ve tried and tested many of the cross-platform solutions out there, like PhoneGap, Xamarin and React. In the end, we’ve always preferred native solutions for both Android and iOS. Let me try to explain our preference in this post.

So what is this cross-platform anyway?

iOS apps are traditionally written in Objective-C or in Swift; Android apps in Java or Kotlin. These are native languages — ones that are supported by the system out of the box. This means that if you’d want to make an app for both platforms, you’d need to know at least two programming languages. Add the web to the mix, and you’ll need HTML+CSS+JavaScript for the UI, and something like PHP or Ruby for the business logic. That’s a mess.

Cross-platform solutions aim to simplify (part of) this problem by using a single programming language for multiple platforms. Those solutions can be split into two categories:

  • The ones that use web technology that is supported by all platforms. These solutions basically load up a mobile browser in the app and perform all logic within that browser, while offering added functionality that traditional website technology does not, such as push notifications or access to the file storage. This category includes PhoneGap (or Cordova), Sencha, and Ionic (a framework built on top of PhoneGap), and uses JavaScript as their main programming language.
  • The other category is often referred to as ‘native cross-platform’ — because the code written by the programmer is automatically translated by a program into native code. This has the advantage that the resulting app can achieve near-native performance, whereas the web-based solution has the overhead of running non-compiled code in a browser. This category includes React Native and the (probably) most popular one: Xamarin.

Those native cross-platform solutions can be further split into two subcategories: the ones that share UI code (the visual part of the app) and the ones that don’t.

  • For example, regular old Xamarin shares the business logic code between platforms but the UI code (and other platform-specific code) is written specifically for each platform. Even though as a developer you are now using a single language (C# in this case) you are still writing separate code for the UI on iOS and Android.
  • Xamarin also offers an API called Xamarin.Forms that allows sharing UI code. Instead of writing separate UI code, you write it using Xamarin.Form’s own markup format which then gets translated to native controls for you. React also falls in this category; instead of writing native views you’ll write React views, and React takes care for the rest.
Writing UI code only once, the React version

The Good

Sounds good, I’m in! All these technologies are rather nifty. Shared code means less work and less learning. That is all true, let’s have a look at the benefits of using either of the aforementioned options:

  • Shared business logic — Write your business logic once, run it on any platform. Google managed to re-use 70% of its code across Android, iOS and the web for their app Inbox, using their own Java-to-Objective-C converter J2ObjC. This vastly reduced the amount of work required to build the apps, reducing costs, and resulting in a shorter time-to-launch.
  • Maintenance — Shared code doesn’t just reduce cost during the initial build, it’ll be beneficial for the lifetime of your app. Every update again. (Or at least, it should… keep reading!)
  • Learn one language — If you’re a developer looking to target multiple platforms, it’s easier to learn a single language (or set of languages — usually a programming language, build script language, and mark-up language for the UI) than two sets of languages.
  • Same team working on both apps — This is a big one. A single team is cheaper, makes project management easier, and works more efficiently. Knowledge is shared more easily within the team. Members of the Android team can help out the iOS team and vice versa, because there is no Android team and there is no iOS team. There’s only one team.
  • Shared unit tests — If you have unit tests (as you should), a cross-platform code base can also share the unit tests. This means less time spent on writing tests, or the same time spent on writing more tests.
  • Works with the web —When using a web-based solution (or a native one that supports the web), then all the above rules also apply for the web platform. Where Xamarin can only share code across iOS and Android, a web-based tool has all the benefits mentioned before also for the web version of your app.

So apparently there’s a lot to gain from these benefits, whether you’re a single developer, a multinational working with multiple development teams, or even a student learning to build your first app. ‘Write Once, Run Anywhere’ it’s often called, and while I won’t argue that it is sometimes a perfect solution for a project, this already sounds a little too good to be true, doesn’t it?

Chet Haase, Senior Staff Software Engineer at Google, puts it eloquently.

Over the years the team at Pixplicity and I have used several of those platforms (with varying degrees of success) and we probably won’t stop trying out new ones in the future. Along the way, we have encountered several major pitfalls that I think should be carefully considered before committing to a cross-platform tool.

The Bad

Ok, so all the big names are doing cross-platform, right? Google created and uses (a lot) of J2ObjC. Facebook created and actively maintains React. Microsoft bought and very actively maintains Xamarin. Then what’s the catch?

Different platforms are different

You can’t build an app for one platform and expect it to get good ratings when you simply copy-paste it onto another platform. I know you want to, and though you technically can, you shouldn’t. Android and iOS are different, Android and iOS users are different, and they should be approached differently. Each platform has their own list of design guidelines and rules to live by, and users will know when you break them.

As Google puts it:

J2ObjC does not provide any sort of platform-independent UI toolkit, nor are there any plans to do so in the future. We believe that iOS UI code needs to be written in Objective-C, Objective-C++ or Swift using Apple’s iOS SDK (Android UIs using Android’s API, web app UIs using GWT, etc.).

Or Facebook, on the very page that promotes React [emphasis mine]:

It’s worth noting that we’re not chasing “write once, run anywhere.” Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach “learn once, write anywhere.

So that means when you want to optimize the UI for each platform specifically, that shared-UI platforms (like Xamarin.Forms) are already out the window. Which in turn means that near-100% code sharing becomes an unreachable goal. More realistically, assume 60% of code being shared across the platforms, depending on the nature of your app.

The web then again is totally different of either mobile platform, or at least it is when used on a laptop or desktop. Screen sizes matter a lot, so does the presence of a keyboard, and so does the interaction when using a mouse vs. a touch screen. Once we get to the bit about performance, you’ll see there are not many benefits to web-based solutions anymore, unless you’re very experienced in web technology and absolutely don’t want to learn a new language.

Note that platform differences are not limited to the visual side of your app. It includes all the features that are present, missing, or different on each OS. There’s a whole slew of features available to Android developers that are not possible on iOS. Think of Android’s rich notifications, open access to Bluetooth, NFC and USB communications, always-on-top views, Instant Apps, launch screen widgets, and probably more. Vice versa for iOS: smart app banners, dedicated encryption hardware, 3D-touch. Others are too different to be unified in a cross-platform wrapper: Picture-in-Picture, ARKit vs. ARCore, the mechanism of playing music, if and how long apps can perform tasks in the background, when and how to ask for permissions, accessing external storage…

Romain Guy, Senior Staff Software Engineer at Google, shares our concerns.

Performance

Faster than native is literally not possible. Native cross-platform code is translated to byte code or native machine code and can therefore theoretically achieve as-good-as-native performance, however, there are often various penalties. Xamarin for example ships each app with a library of functionality that causes some overhead — it might not matter for the smoothness of animations or responsiveness to user interactions, but it will matter in start-up time, memory usage and application size. A simple “hello world” app built in Xamarin can take up a staggering 16Mb (which is 4 times larger than the maximum size of an Instant App!).

‘Near native’ performance? Loading and saving pictures in milliseconds; lower is better. Stats from August 2017

The performance of web-based approaches doesn’t even cut it close. Running a website in a mobile browser or web view has traditionally been bad for performance, and while it has improved tremendously over the years, the difference in responsiveness are not only measurable but also very noticeable. A simple and well-made, web-based app might fool your users into thinking it is native, but however smooth the animations and native-like its UI components are, a flickering screen transition or device rotation will give you away. This has been a major reason why Facebook has invented React. Remember the old, horribly slow Facebook app? That was all web views.

“Unfortunately, because all the rendering is done using web tech, we can’t produce a truly native user experience.”
~ Facebook

Ease of development

This one is a bit of a personal gripe for me as I’ve encountered my fair share of trouble while creating Xamarin apps. The tools have been so buggy and the development process so cumbersome that I’ll have to try my best to keep post from becoming a personal vendetta against Xamarin. Still though, I want to get the biggest one off my chest first: the bugs. Holy IDE’s, Batman, the bugs!

  • Bugs — Android and iOS are solid platforms, but even those have bugs. There are bugs or unexpected or undocumented behaviours in the operating systems, in the development tools, and in the libraries you use. It sucks, but it happens. Add another layer of software into the development process, and you’ll add more bugs. In the case of Xamarin, this list is LONG. There’s a reason we have a shared document titled ‘The Grand List of Xamarin Sh*t’ at our office. It’s not just dealing with more bugs, it’s also that the increased complexity of the toolchain causes a more complex debugging process. Whenever something goes wrong, it is more difficult to pinpoint the issue, to google the issue, and to know if the problem is your code or the platform’s. This will eat up hours of development time that you did not account for.
We have a shared document titled “The Grand List of Xamarin Sh*t” at our office.
  • Immaturity of the tools — The fact that cross-platform toolchains are less matured than the native platforms does not solely result in the higher amount of bugs that they manifest. It also means that they are less complete. Think of the automated code-checks that XCode and Android Lint perform, which warn about bugs and security issues during development. Think of the IDE’s that aid and speed up writing code, that aid in tracking down bugs, tracking down performance issues (memory, cpu, gpu, battery usage, etc.). While other platforms are certainly also releasing similar tools of their own, the native platforms have had a head-start of years.
Advanced Java IDE
  • Slow integration of new platform features — XCode and Android Studio (based on IntelliJ) are tried and tested, always the first to release new features, and are also guaranteed to provide access to 100% of the platform’s functionality that is available to developers. Due to their nature, cross-platform tools will always be behind the curve with every update. Granted, Xamarin has always been very quick to adopt, and they even boldly claim it takes ‘a few hours’ to include new OS features, but issues are a-plenty. There was the time that the Appstore enforced apps to be built for 64-bit CPUs while Xamarin wasn’t stable yet. Also, good luck trying to build an Instant App using any cross-platform solution any time soon.
  • Programming language — There are (online) wars fought over which programming language is considered ‘good’ and which are ‘bad’. Each language has their pros and cons, their fanboys & -girls and haters, their advocates and enemies. But however much personal opinion plays a role in this discussion, some languages are inherently safer than others. No matter how good your codestyle-check or IDE is, there are simply certain bugs that can be made in one language and not in another. Yes, this bit is about Javascript. Javascript (used by React) allows you to make typo’s that are uncatchable by the interpreter, causing runtime error instead of spellchecker-like warnings while writing.
JavaScript thinks truth is just, like, your opinion man.
  • Availability of libraries — Popular cross-platform solutions often have a good package manager that provides a wide array of plugins or libraries. Xamarin’s NuGet repository for example has an amazingly large offer of plugins and includes many popular native libraries. None of these repositories compare to the amount of libraries available for native platforms. The nice thing is that you often can port existing native libraries, the bad thing is that you often have to. And for some of cross-platform technologies this means you’re going to have to have knowledge of the native programming languages, which is what you were trying to avoid when choosing a cross-platform language.
  • Slow coding and running cycle — Admittedly, this argument goes both ways. There are web-based and native cross-platform options that can show code changes pretty much on the fly, and there are those (looking at you again, Xamarin) that take foreeeeever to deploy onto a device or simulator every time you make a small change.
  • White labeling — This one matters when you deploy your app with different branding for different clients. ‘Build flavors’ on Android or ‘Targets’ on iOS — these platforms have easy systems in place for supporting this. None of the cross-platform approaches that I know of support this, so you’ll end up scripting your own solution in the build process — investing development time, and making every deployment more complex.

Expertise

Expertise is a subjective thing. If you’re experienced in Ruby, you’re probably most comfortable creating mobile apps in Rhomobile. If you’ve been programming in Basic for the last 30 years, you can stick to what you know and use B4X. The developers at Pixplicity have years of experience in native technologies, we’ve been programming at a high level for a long time and are regularly teaching our knowledge at our Android Academy and conferences around the world. But that’s just us; your expertise might be in C# or in web technology. That will influence your choice when picking a technology to develop your app, but should it? Certainly yes, but that’s not the whole answer:

  • Learn one language — I mentioned this as a ‘pro’ of cross-platform development. But is it that simple? If you want to write a high-quality app, you will need to know the platforms you’re targeting inside and out. You’ll need to know what the platforms can and can’t do, what their SDKs offer, and even which bugs or peculiarities you have to take into account. For each platform. Often even for each version of each platform. It is easy to under-estimate the amount of knowledge you’ll still have to learn, and to over-estimate what you already know. If you’re an experienced C# developer, all knowledge about .Net and GDI is useless. Actually, learning a programming language is the easy part of app development. It’s a small step from C# to Java, or from Swift to Kotlin. If you understand the concept, the syntax is trivial.
  • Years of experience — Surely those cross-platform languages like Ruby, C# or JavaScript have been around for ages, but those platforms have not. React Native was released in March 2015. At the time of writing it is simply not possible to find a React Native developer with over 2.5 years of experience.
  • Documentation — Any decent cross-platform solution is very well documented. Native development is documented better. They have a larger online community. They have more conferences and more local meet-ups. On Stack Overflow (the massive cheat sheet for all developers) there are 191,918 active questions on Android+Java, 103,641 on iOS+Swift, 59,355 on React, 54,126 on Cordova, 25,976 on Xamarin. Surely this is an indication of community size and engagement, and not of the incomprehensibility of native programming.

Your business depends on it

So by now you know that I have a strong dislike for cross-platform development, and hopefully now so do you. Yet so far I’ve only even covered the practical side of app development. Let’s look at the future, and see how it might affect your business.

Apple and Google have huge teams building their platforms, and they will have for as long as those platforms exist. This is the best guarantee you can get regarding long-time support for the tools they’re offering, and the active continuous development of it. The popularity of the native platforms also creates a larger support for the community around them, and a more steady supply of experienced programmers (should you be looking to hire).

Cross-platform tools however, are fully dependent on the agenda of the companies funding them. None of them give any guarantees about support and future plans. There are no guarantees they will be compatible with the next update of Android or iOS, there are no guarantees that they’ll even exist next month. If that happens, you can only hope that the technology will be handed over to the community and will continue as open source, undoubtedly with a much, much slower pace of development.

“The company hasn’t provided any guarantees that it won’t pull the plug on the project — not just for the foreseeable future, but for the lifetime of your app.” ~ Ariel Elkon about React Native

If the past is any indication of the future, then today’s popular cross-platform solution will be superseded in about two years time. Titanium, PhoneGap and Adobe AIR have all been regarded as the next big thing in cross-platform development. Now it’s React and Xamarin wearing that crown; Progressive Web Apps are probably next.

Notable exceptions

So when should you use some cross-platform toolkit, if at all? Well, there are two big exceptions to the story:

  • Games — More often than not, games are not dependent on native components. They’re using custom UI components that are designed to fit the look and feel of the game anyway, so there’s no pressure to write native layouts. Whether 2D or 3D, games are often built on top of OpenGL, where performance is excellent, where the visual logic makes up a very large portion of the app, which can be shared across platforms. If you’re making a game then yes, you should use something like Unity or Unreal.
  • Rapid prototyping — If you quickly want to test an idea and deploy it to a group of testers, you’re probably more interested in how your app interacts rather than whether it has good performance and all that. Depending on your expertise, a cross-platform toolset can be a perfect fit for creating a prototype in a quick and easy manner.

TL;DR

You were promised 60% to 90% shared code, resulting in faster development and less maintenance. But the development process has slowed down due to inadequate tools, the developers are unhappy, they’re making more components by hand due to lack of libraries, and with every software update things start to break. Deployment takes longer. Testing is inadequate so there are more bugs. Now you have cut development cost by only 20% instead of the expected 60–90%, and on top of that your users are leaving bad ratings.

We’ve seen it happen, and we’ll continue seeing it happen. Surely your mileage may very — nobody’s saying it will happen to you too, but please consider this article when choosing a platform. Clients have come to us with a cross-platform app asking to have it rebuilt using native technology. Not once has it been the other way around.

About the author

Mathijs Lagerberg co-founded Pixplicity at the beginning of 2012 after building a couple of Android apps. The Android OS was still young ‘back in those days’ and it only had a tiny market share. Having programmed in countless languages for the better part of his life, it made sense to dive head-first into this new technology and join a start-up that focussed on building mobile apps. Over time Pixplicity has grown to a creative tech agency that has the privilege of playing with all the fun two-letter abbreviations: A.R., V.R. and A.I.. Still building apps though, but not cross-platform ones.