Native-only development

TL;DR

Three main reasons:

If you think it is a good idea to use Jetpack Compose (or any other multi-platform UI library like Flutter or React Native) to build an Android and iOS application, it is probably because you’ve never developed or used an iOS application before . . . . It is important to respect UI/UX guidelines of the platform and Compose can’t build an application like SwiftUI does. SwiftUI vs. Jetpack Compose by an Android Engineer

Native applications receive updates to their software development kits (SDKs) faster than cross-platform frameworks. This means the latter can face potential delays in incorporating new functionalities or taking advantage of the latest platform enhancements. Native vs. Cross-Platform Development

Shared code . . . can lead to performance issues, lack of native look and feel, and complications with debugging and tooling. Slack’s mobile developers wanted to work with native language features and APIs, and build best-of-breed apps for each platform . . . . Stabilize, Modularize, Modernize: Scaling Slack’s Mobile Codebases

Other reasons (privacy, cost): Making Ollie: Creating a local iOS app in a time of React Native.

When cross-platform makes sense:


Source: The Fundamental Problems with cross-platform frameworks

Overview of cross-platform approaches:

Also, except for PWA (progressive webapp), to develop a cross-platform app for iOS still requires use of Xcode and macOS.

Below are additional articles on why various cross-platform solutions have not panned out for their adoptee companies.

React Native

React Native allows Javascript developers to leverage their skills to develop for mobile. React Native uses platform-specific native UI elements to build cross-platform apps. The original React Native architecture had performance issues interfacing Javascript with native APIs. The JavasScript Interface was introduced with React 0.68 to address these issues. The benchmark app released with React Native 0.72.0 showed that the new architecture has a 0-8% performance improvement on Android and a 13-39% performance improvement on iOS.

Articles below discuss why React Native has not panned out for its adoptee companies beyond the performance issue:

Flutter

Flutter is a cross-platform UI toolkit embedded in an “ambient” native app, allowing applications to interface directly with underlying platform servicess. Instead of using native UI elements (widgets), Flutter implements its own, customizing them to mimic the UI elements of each platform, which it then renders to the screen. Flutter originally rendered using the Skia 2D graphics library, but due to animation jank issue, especially visible on iOS, Flutter introduced a new rendering engine, Impeller, which pre-compiles shaders and utilizes modern graphics APIs (Metal and Vulkan). The first-adopter preview for iOS was made available in Aug. 2020, with Flutter 3.3. The Android preview was made available in Nov. 2023, with Flutter 3.16.

A Flutter app is written in the statically-typed Dart language. Dart automates bridging to native code/SDKs for languages following the C calling convention (C/C++, Rust, Go, Swift and Objective-C) using FFIgen and with JNIgen for Java Native Interface binding.

Kotlin Multiplatform – Compose Multiplatorm

Kotlin Multiplatform is a multi-platform, not cross-platform, solution. KMP (née KMM, Kotlin Multiplatform Mobile) helps Android developers venturing into iOS development maintain a common domain/business-logic code base (in Kotlin), while keeping code to access the physical device, including the screen, separate and native.

Source: Kanivets

Compose Multiplatform (CM), a Jetbrains-maintained library built off Google’s Jetpack Compose, allows sharing of declarative, reactive UI code. In addition to Compose, Google has also released a multiplatform version of Jetpack Collections (implementing Java collections API) and DataStore. Compose Multiplatform, combined with KMP and the rest of the Google multiplatform libraries, is close to providing a cross-platform solution. Whereas React Native apps build with native UI elements and Flutter widgets mimic those of the native UI elements, Compose Multiplatform employs the Google Material Design language across all platforms.

UI rendering on Compose Multiplatform is done using the Skia 2D graphics library (Skiko on iOS), which originally powered Flutter, but which Flutter is replacing due to its startup animation jank. To SwiftUI, a Compose UI View is treated as a UIKit View. SwiftUI state managment must then be manually conveyed to a ComposeUIViewController as with using any legacy UIKit View (see Compose Multiplatform —- managing UI State on iOS). Compose for iOS is now in alpha, usable but not yet production ready. As for the use of Google Material Design language, “It is important to respect UI/UX guidelines of the platform and Compose can’t build an application like SwiftUI does.” – SwiftUI vs. Jetpack Compose by an Android Engineer.

KMP, being Kotlin compiled to Objective-C, does not fit smoothly with Swift development:

The integration burden to be iOS/Swift aware is also born on the Android/Kotlin side:

Additional reported iOS-side frictions:

KMP+CM is most useful in an enterprise environment, where the investment in project build process could pay off over time and across projects, and on apps where the business logic largely resides on the front end with heavy client-side persistence and offline support:

Multiplatform development relies in large part on managing the build process, to juggle and interface code between platforms. This is true for both KMP and CM. While JetBrains is striving to automate the build setup with Kotlin Multiplatform Wizard and to make the multilingual development experience itself more integral by introducting Fleet, a “polyglot IDE”, still, for this course, do we want to focus on finagling the build process or do we learn native platform development, which all cross-platform, multi-platform frameworks in the end fundamentally depend on when it comes to accessing the device (see for example, Kotlin Multiplatform Mobile — Location Permission and Location Service Setting)?

Cross-platform frameworks comparison

With the performance bottleneck of React Native and the animation jank of Flutter resolved, the choice between React Native, Flutter, or Kotlin+Compose Multiplatform for cross-platform development boils down to:

  1. language choice:
    • Javascript (or Typescript as of React Native 0.71), with the JSX extension,
    • Dart, or
    • Kotlin. Kotlin+Compose multiplatform currently presents a larger overhead in project setup and a less mature path in multiplatform integration, especially disadvantaging the iOS side.
  2. UI/UX look and feel:

With all three, methods to access the device directly, for example device sensors, must still be developed in the native platform languages.

Progressive Web Apps


Prepared for EECS 441 by Sugih Jamin Last updated: January 11th, 2024