Multi vs Cross Platform in the age of Flutter

Since the early days of mobile app development there has been a robust debate about whether to build apps using native platform technologies or cross-platform technologies. Flutter has created a new dimension to this debate as it shares characteristics of both multi and cross platform.

The promise of Flutter and interest in the dev community means it is worthwhile enumerating this debate again within the context of Native vs Flutter.

Here are the factors we think are important when looking at cross-platform mobile development:

  • Best in class native app experience vs easier toolchain.
  • Platform expertise vs abstraction costs.
  • Platform specialised programming languages vs generalist language.
  • Latest platform developments vs playing catch-up.
  • Multiple code bases & testing efforts vs single codebase and incremental testing effort.
  • Platform specific test frameworks vs general test frameworks.

A little background on Flutter

Let’s start with a very quick overview of why Flutter is different to other cross-platform efforts. Simply put, Flutter adopts a similar approach to mobile game engines and breaks down into these three pieces:

  • iOS (.ipa) and Android (.apk) apps that act as runners but do not contain the compiled app code itself.
  • A native runtime engine handles low-level responsibilities such as drawing UIs and interop facilities for device and/or platform library access. For iOS this is engine is delivered via LLVM and Android via NDK.
  • App code compiled to an ARM library which, together with the engine, creates the app experience.

This is a significant departure from cross platform with Ionic/Cordova running in a web view and ReactNative with a JavaScript core and interops with native UI components.

The reason why Flutter has brought more attention back to cross platform is that it:

  • Runtime performance is very fast and solves the problem of lag that continues to plague JavaScript-based solutions (Ionic/Cordova or ReactNative).
  • Flutter’s toolchain means it is possible to develop on emulators and devices (like native development) vs using Chrome dev tools for mobile app development (Ionic/Cordova or ReactNative).
  • First-class IDE support. There is significant investment in tooling, which is what to expect from Google these days.
  • Google’s pedigree in mobile operating systems gives legitimacy to Flutter. It has been conceived by illustrious Google engineers such as Adam Barth.

Below we restate our opinions about native vs cross-platform and reassess these in the context of Flutter.


Best in class native app experience vs easier toolchain

What is our opinion?

Native apps offer the best user experience based on speed, platform conformity and use of latest features. Cross platform offerings are concerned with using a programming language and runtime that come from a non-mobile world on the basis that this simplifies development.

How does this look with Flutter?

On the surface, Flutter is just a variation of what has come before. Indeed, you can re-purpose statements from React, Cordova or Xamarin to describe Flutter.*

In this regard, Flutter doesn’t challenge our current thinking.

However, there are 3 areas where Flutter’s story is different and more interesting.

Firstly, it is disrupting how native developers see their own native toolchains.

Flutter’s amazing Hot Reload is what native developers have needed for a long time. Source code changes are reflected on the device/emulator instantly. Flutter is leading the way for how native app development should be. (See Android Studio’s recent updates to instant run http://bit.ly/2N6YcTo).

Secondly, Flutter is achieving app performance that native developers would be happy with. Even on resource constrained devices like Android One, Flutter sample apps are smooth far beyond expectations.

This is possible because Flutter compiles to ARM instructions (via NDK for Android and LLVM for iOS). Even more innovative is the unique rendering model employed by Flutter whereby rendering is achieved in one pass through the widget (aka view) hierarchy. In addition the concept of stateless vs stateful widgets allow for caching of layouts. However, Flutter is still young and the jury is still out when it comes to performance.

Thirdly, Flutter uses a newer modern programming language.

We have a bias against JavaScript as a language. (We don’t have time to go into that topic here unfortunately.) What’s interesting about Flutter is that its use of the Dart language means developers get a modern and mature programming language that is also very familiar. (We will write an article about Dart in the future.)

What does this mean?

Whilst it is clear that Flutter is a more compelling departure from previous cross-platform efforts, it can’t shrug off some of the deficits which continues to form our thinking that Flutter remains a compromise between best in class native experience and toolchain simplicity.

Flutter’s UI widgets are a facsimile of the native widgets. As such they don’t always feel quite right. Also, Flutter will be in a constant state of catch-up as it has to react to innovations and improvements to iOS and Android. For example, Flutter doesn’t (yet) give you access to ARKit/iOS or ARCore/Android.

* When substituting the name of other tools with ‘Flutter’, the statements made by other cross platform tools seem to hold pretty well.

“[Flutter] R̵e̵a̵c̵t̵ ̵N̵a̵t̵i̵v̵e̵ lets you build mobile apps using only [Dart] J̵a̵v̵a̵S̵c̵r̵i̵p̵t̵ . …letting you compose a rich mobile UI from declarative components.” (React Native https://facebook.github.io/react-native/)

“[Flutter] A̵p̵a̵c̵h̵e̵ ̵C̵o̵r̵d̵o̵v̵a̵ is an open-source mobile development framework. It allows you to use standard [Dart] w̶e̶b̶ technologies — H̵T̵M̵L̵5̵,̵ ̵C̵S̵S̵3̵,̵ ̵a̵n̵d̵ ̵J̵a̵v̵a̵S̵c̵r̵i̵p̵t̵ for cross-platform development.” (Cordova http://bit.ly/2Br2enX)

“Deliver native Android, iOS, and Windows apps with a single shared [Dart] .̵N̵E̵T̵ code base.” (Xamarin)


Platform expertise vs abstraction costs

http://www.duckychannel.com.tw

What is our opinion?

Platform expertise means access and understanding of APIs and SDKs as the platform developer intended. As such Native development entails no abstraction cost. All cross platform efforts are attempts to abstract the developer away from the realities of the underlying platforms. The cost to developers is that the cross platform tool is either an unknown black box or the developer has to juggle some knowledge of both native platforms and the cross platform abstraction.

How does this look with Flutter?

Developing with Flutter doesn’t change the limitation of cross platform tools — they offer a subset of the features available to native developers. If you want to go beyond this subset, you need an interop mechanism and platform expertise. Flutter is no different and employs a plugin mechanism to allow interoperability with native code.

However Flutter is distinct.

Firstly, you don’t have to particularly worry about the underlying platforms because Flutter takes responsibility for a lot of what the platforms would otherwise do. Flutter brings its own engine including the Skia graphics library for drawing all UI elements. The Flutter framework takes responsibility for the entire UI rendering. You don’t need to understand both differences between Android and iOS views and rendering because you use Flutter’s widgets. The Flutter widgets also make it easy to roll your own.

Secondly, another common abstraction cost comes why profiling cross platform app performance. The cross platform runtimes (often of the areas of most concern for performance) are typically not straightforward to possible to profile with native iOS and Android profiling tools. Falling back to Chrome dev tools is a common profiling approach in these cases.

Flutter does bring its own profiling tools (http://bit.ly/2PXMIDo) — we don’t know enough about these yet to form an opinion, so that might be a subject for a future post.

What does this mean?

Flutter does not use native platform UI rendering and as such the framework is not so much abstracting the underlying platform as offering an alternative runtime.

However there is still need to access underlying device services and, like other cross platform frameworks, this is done via a plugin mechanism. The cost of abstraction is there even if it is less than with other cross platform technology.


Platform specialised programming languages Vs generalist language

What is our opinion?

Swift and Kotlin (with Android extensions) are the de facto languages for iOS and Android platforms. Apple and Google have invested heavily to make sure these languages are optimised for compile & runtime performance with excellent support for tooling, documentation and community engagement. Cross platform approaches explicitly aim to take languages from outside the mobile development context and create an environment whereby they can be reused in a native setting.

How does this look with Flutter?

Flutter apps are built using Dart, a relatively unknown programming language. Dart’s origins date back 7 years and the initial hope was for it to be a modern alternative to JavaScript. This never materialised as the Dart VM never made it into Chrome. Today Dart is typically transpiled into JavaScript or compiled into machine code. The Dart VM lives on but has less focus than before.

Therefore it is easy to see that Dart is very much in line with it’s cross platform cousins which use JavaScript or C# — it is clearly a language from outside the mobile development context.

However, the recently released Dart 2.0 is a “reboot” of the language specifically “to make mobile and web development more enjoyable and productive” (http://bit.ly/2MLR828). Dart has evolved to be a language to specifically serve Flutter and Angular Dart. This is in contrast to languages like JavaScript that were never intended for mobile development.

What does this mean?

Dart is fortunate in that it has been rebooted largely to serve Flutter and Angular Dart. Indeed, Flutter development owes much to the ability to Just-in-Time (JIT) compile, i.e. when hot reloading, or Ahead-of-Time (AOT) compile. This is the basis of Hot Reload.

Dart is easy to learn. Its asynchronous programming model and the fact that it is a single threaded language will be especially familiar to JavaScript developers — it even shares the async/await syntax.

However, the prospect of yet another programming language could very well be a barrier for acceptance.

Latest platform developments vs playing catch-up

What is our opinion?

Native app developers are always benefiting from the latest platform updates and capabilities. Cross platform approaches can only react to changes. Depending on the size and significance of the platform changes, there can be significant delays before a cross platform app reflects what native apps have already embraced.

How does this look with Flutter?

Once again, Flutter falls inline with the other cross platform approaches. As iOS and Android improve their capabilities the Flutter team must respond to bring these improvements to the framework.

One advantage that Flutter has over the others is that Google can choose to let Flutter keep up with Android. This isn’t a certainty as Flutter and Android teams have separate roadmaps and priorities. However, the recent update to Material Design saw Flutter support at the same time as Android and iOS.

Less encouraging is the degree to which Google’s own services are in relatively early stages of support. To take one example, Firebase support in Flutter/Dart is still quite far behind that of iOS and Android.

What does this mean?

Flutter’s relationship with Google means that it might have an edge on other cross platform frameworks. However, Flutter remains a few steps behind native app development with regard to offering latest features. As evidence, Flutter doesn’t not provide access to Augmented Reality capabilities for iOS or Android. Machine Learning features in the latest iOS and Android versions are also not available.

This remains a downside to cross platform development approaches.


Multiple code bases & testing efforts vs single codebase and incremental testing effort

What is our opinion?

Building the same app twice is a reality for native development. Aside from the additional effort and cost, it is also challenging to keep feature parity for two apps over time. However, stories from the trenches reveal that cross platform code does not achieve a one-size-fits-all promise.

Supporting platform UI and interaction differences start to erode the allure of a single codebase. UI glitches that are platform or device specific also lead to more and more platform specific code. Performance can also be challenging across a broad range of devices and OS versions with one codebase. We look forward to a day where more code can be shared across platforms. We aren’t convinced today’s cross platform approaches are the answer.

How does this look with Flutter?

So far it looks like Flutter runs consistently well on different mobile OSs and devices, largely thanks to its approach to UI rendering. In this regard Flutter seems to offer the advantage of a single codebase.

What can’t be avoided, however, is the need to include OS specific considerations in the Flutter code. Applying the correct iOS or Android look and feel for example, or using iOS vs Android widgets in the UI.

What does this mean?

Like other cross platform approaches, Flutter means a single code base for iOS and Android. This does mean that the code still has to take care of differences in the UI presentation on the supported platforms.

Whilst Flutter is pretty new, there aren’t a lot of best practice and established patterns for managing this sort of variance in the code. It falls to developers to manage these difference cleanly and in a maintainable way. Inevitably in some cases this will lead to a bunch of spaghetti. However good practices will emerge as Flutter increases its footprint.


Platform specific test frameworks vs general test frameworks

What is our opinion?

Testing mobile apps has some unique challenges. Unit tests run in isolation, instrumented tests require access to platform services or libraries. Integration tests need to be run in a headless mode or on device. Native developers have access to test frameworks that address these challenges head-on. Cross platform developers have to use non-mobile test frameworks or general blackbox testing via appium or something similar.

How does this look with Flutter?

Testing Flutter apps does not make use of native testing frameworks. Instead testing is done using Dart unit test mechanisms and Flutter specific unit testing packages. These packages support testing Widgets (i.e. UI Views) and black box integration testing. Widget tests are run outside the context of an app whereas integration tests must be run on a device or in an emulator.

What does this mean?

The backing of Google become evident when it comes to testing. Flutter goes beyond what other cross platform frameworks offer and puts testing support in focus for Flutter.

With other cross-platform projects, testing is not a central topic. There isn’t any specific guidance about testing in the React Native documentation. Ionic has a blog post to cover the topic but not more. They seem to leave it up to JavaScript test frameworks like Mocha or Jasmine. Xamarin seems to have some testing support but I kept finding dead links in the documentation — like to https://bit.ly/2wQO5f6.

This puts Flutter again somewhere in the middle of native capabilities and cross platform realities. Like other aspects of Flutter, the framework profits from a certain level of self containment.


TL;DR

At Snapp, we feel comfortable with our position that cross platform approaches represent a series of compromises and shortcomings compared to native development. We have long held the opinion that ‘silver bullet’ claims made by cross platform advocates do not materialise in reality. Recent departures from cross platform approaches by the likes of AirBnB are good examples of this.

Flutter is an interesting initiative from Google that has ambitions that go far beyond the mobile device. As with all new technologies, it will take some time to see the strengths, weaknesses and realities of Flutter in the real world over time.

We will be watching Flutter with interest.