When building mobile apps, there are many choices to be made. The first, very important choice is what platform to build the app in. Should it be native development, hybrid technology, or maybe just building a mobile website? There is no right or wrong answer to this question. It really depends on the specifications & requirements of the app, and the problem the app is trying to solve.
In this blog, we will discuss the key differences between four different mobile development technologies we often advise to use at Triple: native iOS & Android, Flutter, React Native and progressive web apps.
1. Native iOS and Android
Seamless user experience and re-using SDKs & framework
Native app development is a process of creating mobile applications for a specific platform using the respective programming languages and tools provided by the platform. With native app development for iOS and Android, businesses can take advantage of platform-specific features provided by Apple and Google and thus offer a seamless user experience to their customers. For iOS development, Xcode is used to write apps in Swift. Xcode contains support for all native iOS SDKs. iPhone, iPad, Apple TV, and Apple Watch share the same set of SDKs and frameworks, and code can be reused between those devices. For Android development Android Studio contains support for all native Android SDK’s and is used to write apps in Kotlin. Android phones & tablets, Android TV and WearOS also share the same set of SDKs and as with iOS, code can be reused between the different Android devices. Both SDKs provide a specific set of UI components & interactions that are familiar to the user. Different UI components apply when targeting another OS though, like iPhone vs WatchOS or Android phone vs Android TV.
More control, in-depth frame rate optimization and shorter time to market
By using the native development environments, developers have more control over the CPU, memory, network, and battery usage. Both development environments also provide tools to do in-depth optimization of framerate to ensure even complex interfaces & animations reach 60 frames per second, even on older devices. In general, the development cost per feature tends to be higher than hybrid development due to the 2 separate development environments.
Access to core device functionalities such as Location, Bluetooth, and OpenGL drawing are directly available with the frameworks that Apple & Google provide. Both environments also provide direct access to newly released functionalities like integration with Voice Assistants or Augmented Reality. Being able to utilize these technologies directly, without a dependency on hybrid development wrappers, reduces the time-to-market.
In charge of updates and more flexible app maintenance
A few months after an iOS OS release, Apple enforces the use of the newest Swift version when submitting updates to the App Store. This forces developers to ensure their app works on new devices, using the latest (optimized) APIs. Without a dependency on hybrid development, developers have more control over when to update to the newest Swift version before Apple enforces it.
Google maintains a lower update frequency, though they also enforce the use of a minimal API version when submitting to the Play Store. Generally, when using native development, the effort for ‘app maintenance’ is low. Both Apple and Google provide tools to upgrade code in order to be compatible with new SDKs. User interface changes required for new device form factors, such as the iPhone X notch or new foldable devices, require little effort, reducing the time-to-market.
2. Flutter
Ease-of-use, fast development cycle & testing and lower cost-per-feature
Flutter is an open-source mobile app development framework developed by Google. It allows developers to build high-quality, native mobile apps for Android and iOS with a single codebase. The framework uses a reactive programming model and offers a rich set of pre-built widgets that allow for fast and easy app development. Its popularity has been on the rise due to its ease of use, fast development cycle, and cross-platform capabilities.
Flutter apps are written in Dart and are supported by a variety of IDEs, including Android Studio. Flutter draws directly to the GL canvas and is therefore highly performant. Integrations with core mobile operating systems APIs are done separately, using wrappers written in Xcode using Swift and Android Studio using Kotlin. Flutter and the platform native host share a channel to communicate requests and responses. Native UI components for Android and iOS differ in behavior and functionality, but this is covered by Flutter by implementing both Material and Cupertino widgets within the core of the SDK. Most modern apps use a design that is almost identical on both iOS and Android, therefore most widgets do not require customization for platform specifics.
Flutter is developer friendly, it features a hot reload feature that allows for rapid iteration and testing within a couple of seconds. This makes the build cycle faster than the complete cycle of a native build, which may take longer. However, this is only available for UI components and not for other functionalities. In general, the development cost per feature without core device functionality will be lower than native development due to the hybrid development environment.
Integrations through native wrappers or through open source
Access to core device functionalities such as Location and Bluetooth is available through the native wrappers. Some integrations, like the usage of the camera, are directly possible with Flutter without using a wrapper. Most functionalities are already available as opensource modules, some of them pre-built by the Flutter team. The use of open-source modules can speed up development. Our experience is that the available native modules are sufficient for basic functionalities. For applications that require deeper integrations or new functionalities provided by Apple & Google, customization of these modules is often required. Integration with services from Firebase (owned by Google) are provided out of the box. Firebase is our preferred solution for mobile analytics. Writing or customizing a native module for iOS & Android, and exposing it through a wrapper requires a higher development effort than just integrating the functionality directly in the app, as you would do in a native app.
Easy conversion to JavaScript
Google made Flutter apps available for web using Hummingbird. Hummingbird is a web-based implementation of the Flutter runtime. Using Hummingbird, it is possible to compile Dart code to JavaScript without making any changes to the code. When the Dart code is compiled to JavaScript, the application is ready to use for web and desktop. The supported platforms are Windows, MacOS and Linux. No official TV support is available, and although you probably can make it work, it is not recommended.
Additional work for updating and working on large range of OS versions
The maintenance requirements as described under Native iOS & Android are the same for Flutter apps. As Flutter is built on top of the iOS & Android SDK, there’s a delay in updating as Flutter must be updated to the new SDKs before the app itself can be updated. Adopting new device form factors, can require additional work for custom components. Flutter also must update their Material and Cupertino widgets to adhere to the latest standards, which will require some time. Both Apple and Google provide early access via Beta programs to the new SDK features, which should give Flutter enough time to implement the changes before they are available to the public. As Flutter draws directly to the GL canvas and has their own implementation of the widgets, it works on large range of OS versions.
3. React Native
Platform differentiation effort and knowledge of several programming languages required
React Native is an open-source solution initially built by Facebook internally, on top of the iOS & Android SDKs. The development requires multiple development environments. The user interface and backend communication are usually built using JavaScript. Integrations with core mobile operating systems APIs are created separately using native code, which is exposed to the JavaScript environment using bridges, or JSI when New Architecture is enabled. The bridges are written in Xcode using ObjC (Swift in future releases) and Android Studio using Java or Kotlin. User interface guidelines on iOS and Android differ. This means that although the user interface for both platforms can be written using 1 language, differentiation for platform-specific design and behavior is often still required. The solution has hot reloading available, for a better developer experience.
React Native provides a basic set of shared UI components, but an additional customization effort is required for some details. React Native offers platform-specific APIs to write code for each platform. Developers working on the mobile app will need to have sufficient knowledge of both platforms. The native modules are often written using outdated languages. Apple has moved to Swift, and Google to Kotlin. Writing the native API integrations with these modern languages is possible, but adds an additional layer of complexity, requiring 5 programming languages. When writing the bridges and the code inside using ObjC and Java/Kotlin, the developer still needs to know about 3 programming languages and the intricacies of both mobile platforms. You could, of course, decide to have these modules built by separate developers, but this requires more communication. Generally, the total development effort for features without native wrappers will be lower than if the feature would be built using a native iOS & Android development, due to the ability to share the JavaScript code.
Faster development with opensource modules
Access to core device functionalities such as Location or Bluetooth is available through the native modules. Some functionalities are already available as open-source modules, speeding up development, and for some functionalities, these modules must be developed. In our experience, the available native modules are usually sufficient for basic functionalities.
Additional work for updates and new functionalities
For applications that require deeper integrations or new functionalities provided by Apple & Google, customization of these modules is often required. For the native modules, we often see that either forking the native module and adapting the code might be required or the integration of the module needs to be duplicated in the JavaScript implementation. Writing or customizing a native module for iOS & Android and exposing it through a wrapper requires a higher development effort than just integrating the functionality directly in the app, as you would do in a native app.
The maintenance requirements described for both Flutter and Native iOS & Android development are the same for React Native apps. As it is built on top of the iOS & Android SDK, it must be updated to the new SDKs before being able to update. Adopting new device form factors can also require additional work. The shared UI code will often need device-specific adaptations to update the UI for these devices. Additional maintenance might be required due to the open-source nature of the native modules currently available. The open-source native modules used by React Native are often maintained and supported by a select group of people. If the project is no longer actively maintained, there is a risk that the native module is not updated to support new functionality and APIs provided by Apple & Google, that it is no longer patched for security issues, or that it is using deprecated methods. Fixing these native modules is possible, yet requires additional development effort.
Independency leads to reduced time to market
Access to core device functionalities such as Location, Bluetooth, and OpenGL drawing are directly available with the frameworks that Apple & Google provide. Both environments also provide direct access to newly released functionalities like integration with Voice Assistants or Augmented Reality. Being able to utilize these technologies directly, without a dependency on hybrid development wrappers, reduces the time-to-market.
More risk due to open nature JavaScipt & NPM
React Native uses Node Package Manager (NPM) as its dependency manager. Every dependency added to the project will expose you to security risks. Although this is also true for other dependency managers, the open nature of JavaScript & NPM increases the risk. Dependencies are needed for native modules and are often used for JavaScript code itself. There are ways to lower the risks, but they require effort.
4. Progressive web app
Access to some core functionalities possibly difficult
A Progressive Web App (PWA) is a mobile website complying with new HTML5 standards for things like offline usage and refreshing of data in the background. They are developed using HTML and JavaScript and run in a mobile browser. Access to core device functionalities such as location or Bluetooth is difficult, as they have to be exposed by the browser by complying to HTML5 specifications, Safari on iOS and Chrome on Android. On iOS, features such as Geofencing, Notifications, Bluetooth, and Access to contacts are currently not supported. Android does support some of these features, but Apple has historically been slow in adopting new HTML5 specifications.
Distribution through own website not ideal
The existence of both the App Store and Play Store has given customers clear destinations for where to download new apps. PWAs right now need to be installed through an action on your website. This way of installing your app is not common for a large majority of users and could lead to confusion on how to acquire the app. PWAs also don’t have the benefit of the standard store pages with descriptions, screenshots and app previews.
5. Our vision
At Triple we often get asked about our technology vision for mobile app development. All in all, we can only conclude that every platform has its pros and cons. The right decision for a specific platform can only be made by carefully considering the specifications and requirements of the app that is to be built, the problem it is trying to solve, and external factors like the appointed developers and future maintenance. Based on these, we advise clients on the best technology for their problem.