By Rohmad Sasmito, Senior Product Engineer at Zero One Group
One of the most common requests we, Zero One Technology (ZOT), get from our clients is to build cost-effective MVPs. We believe that building hybrid mobile apps fits the bill in terms of speed and cost.
Previously, our approach had been to use Ionic as our go-to mobile hybrid application solution. We have been developing an Ionic-based application for the last five months. As we added more and more features into the application, we found a number of challenges in building the application using Ionic. In particular, these include:
- Limited possibilities for customization. We can only customize exposed properties. For example, when we want to use a Title component, it is only possible to change some of the basic properties, such as the color. Ionic makes it impossible to modify some properties due to the removal of shadow DOM piercing.
- Inconsistent solution in different stacks. A particular solution that may work in Ionic Angular, may not necessarily work in Ionic React.
- Lack of community support. The community support in the official repository is not as active as other comparable projects. A lot of the issues are still waiting for answers.
Considering the problems mentioned above, we spent some time looking into different hybrid-app solutions. We tried to build the same application with three different hybrid stacks. In this blog post, we will discuss a few alternatives along with their pros and cons.
Case Studies with Nx Monorepos
Nx has been a huge productivity boost in our development process to build products in a monorepo, and it comes with a lot of advantages. We can easily generate high-quality project skeletons that allow us to be productive immediately. We are happy to say that our experience has been overwhelmingly positive on Nx. For the comparisons to be meaningful for ZOT’s use case, we have embedded each hybrid stack in its own Nx monorepo.
Comparison Ionic, React Native, and Flutter
In this blog, we want to discuss how we build applications in different hybrid stacks in Ionic, React Native, and Flutter. We will discuss the advantages and disadvantages of each solution while assessing whether or not a framework is a good fit for the use case.
We decided to investigate the comparison of each solution based on a real use case. We have built this over a single monorepo, which you can see here. The final product is similar to the image shown in the banner above. We built it as simple as possible and our focus is to know more about the development experience of each stack.
In the following sections, we will compare each solution by explaining how we build app components in each stack. The components we will discuss are Avatar, Tabs, Header, and Card. In Ionic and React Native, the components are called Components, whereas in Flutter they are called Widget as in the native term.
In Flutter we can build Avatar using the block code below. Since we would have to use Dart to develop using Flutter, its syntax is the odd one out compared to JS-based stacks. We need to register assets folder into pubspec.yaml file.
These codes would be reasonably long compared to Ionic or React Native. However, Flutter has built Plugins for editors like VSCode as a remedy, which improves the development experience considerably.
Flutter Widget often uses a Container, similar to div in Web. Container has properties such as padding, margin, color, width, and height. Most flutter widgets use decoration property to customize the styles. In this case we used BoxDecoration as it provides a variety of ways to draw a box.
Whereas in React Native, we can build an Avatar component using codes like below. Image is a built-in component in React Native to display an image. And inside of Image, we could place an image asset using require into a source attribute.
To add design, we could use a StyleSheet. StyleSheet is an abstraction similar to CSS StyleSheets.
As mentioned above, we are unable to use rem units in React Native. For the width and height, we use pixels or percentages instead.
In the following sub-section, we describe the tabs in the example application, which is composed of a row of three buttons.
Figure is our own component that receives parameter count and title both in string type. IonGrid is a powerful mobile-first flexbox system used for building custom layouts. IonRow are horizontal components of the grid system and contain varying numbers of columns. They ensure the columns are positioned properly.
However, when we want to build a component in Flutter, it would look slightly different. Dart and Flutter are type-safe, and Flutter Plugin will let us know whenever the types do not line up. Also, note the use of the const keyword, as we are not using declared variables.
Row in Flutter is a widget that displays its children in a horizontal array.
In React Native, It looks pretty similar to Ionic. It is fairly simple even though React Native requires the use of built-in components. The difference to Ionic is we cannot use div. Instead, we use View, which is a container that supports layout with flexbox, style, some touch handling, and accessibility controls.
Though it looks like an Ionic component, inside of View we put children that are called Figure component. The difference is only the background parameter, since we cannot use :nth-child in React Native like in Ionic.
Header is a light-colored box with a title on the left and a small action button on the right side. In Ionic, it has the codes shown in the image below. There is an IonRow on the outside, and on the children’s property, it has IonCol. Inside it, there is a div with a tag paragraph and IonIcon to display an icon.
As mentioned above, we use a Container in Flutter as we need to give color, and padding. On the children property, we place a Row to display the title and an action button, which will be laid out horizontally. GestureDetector is a widget to detect gestures to make the icon clickable.
In React Native, to build a header with a title and action in horizontal view, we would use View, and place a couple of Text and Icon like in the image shown below.
We do not use any libraries to handle icons. Instead we are only importing an svg. because it was not as straightforward to add an icon library. Therefore, we prefer to only import svg, just like what we did when building a React application.
Card is a box that contains post articles such as avatar, date, username, title, comments, likes, and share button.
In Ionic (code), there is an IonLabel, which is a wrapper element that can be used in combination with other built-in components such as ion-item, ion-input, and ion-toggle. The position of the label inside of an item can be inlined, fixed, stacked, or floating.
For Flutter (code), the codebase may look similar to the Ionic counterpart. You may also notice we are using an Expanded widget. Expanded is a widget that expands a child of a Row, Column, or Flex so that the child fills the available space. Using Row, we split the box into 2 parts in our Flutter codebase. On the left side we placed an Avatar Image with defined size, and on the right side we placed date, username, description, comments, likes, and share button. We also used Expanded to fill up the remaining space on the right side of the box.
As for React Native (code), there is nothing new in the codebase. We simply use View, Text, SVG Icon, and other components we have mentioned before.
We have explored how to build the same application in three hybrid stacks. The initial setup of developing them was fairly straightforward. However, the hardest part is keeping it simple when we add more and more features to the app, especially when the UI becomes complex. For our use case, it is important not to be confronted with a stack-specific development blocker. For that reason, we very much value the ability to easily find solutions on Stack Overflow and a responsive community on the project’s repository.
When we look at the Ionic official repository, we see a lot of open, long-unanswered issues. This indicates that the Ionic community at Github is less responsive. Although we often find answers on Stack Overflow, they are often framework specific.
When we look at the official Flutter forum, we see that many issues are still open like Ionic. However, upon further inspection, it looks like the community is active enough to respond to each issue. Furthermore, this technology is made by Google, which has a big supportive community and staff dedicated to maintaining their open source projects. So if we were to build a mobile application with Flutter, support would be quite low in our list of worries.
When we look at the official React Native forum. We see that the community activity is comparable to that of Flutter. And since React Native was built by Facebook, we also would not need to worry much about community support.
The hybrid-app solutions, Ionic, React Native, and Flutter have been growing fast in popularity. These technologies provide us with fast development at a relatively low cost. These solutions also give us the ability to create beautiful, high-performance apps that work everywhere.
Ionic’s guiding principle is to use the web platform and embrace open standards wherever possible. When we build an app with Ionic, we will learn and apply the tools and languages of the web, using a framework designed to deliver great performance on mobile, desktop, and especially, the web.
Flutter, in contrast, has chosen to go at it alone, creating a self-contained ecosystem that is at odds with the common languages, toolsets, and standards found in the broader hybrid app development world. Thus, if we choose Flutter, we will be learning the Flutter way of doing things. Of course, there are clear benefits to a custom architecture that has one single purpose, as we’ve seen in some of their impressive early demos.
Ionic is very popular as it eliminates the learning of a new language factor whereas Flutter needs the developers to learn Dart programming language in order to build cross-platform apps. Although, when it comes to building highly graphical apps, Ionic is never the first choice of the app developers; React Native comes into play in this case. Flutter is new compared to Ionic and React Native but is soon getting the recognition it deserves.
Consideration Upon Choosing a Framework
Choosing the right framework for a company like ZOT can be challenging. However, to simplify the initial stages of building a mobile application, we try to come up with a rule of thumb for choosing a framework depending on the situation.
We would suggest using Ionic, when:
- The business needs to build similar applications for mobile, desktop and web at a low cost and/or with a tight deadline.
- The business requires good web performance.
Flutter when the business:
- Requires good mobile-app performance with a lot of interactive features.
- Aims to continually build upon and provide long-term support of the mobile application.
- Requires an optimized application size.
- Is not terribly concerned about web performance.
We would try to avoid React Native for the following reasons;
- Too much dependency with other external libraries.
- Built-in components that are not as customizable.
- Many deprecated dependencies in older versions.
- “AccessibilityInfo .” React Native, https://reactnative.dev/docs/accessibilityinfo
- “Dart Api Docs.” Flutter, https://api.flutter.dev/index.html
- “Facebook/React-Native.” GitHub, https://github.com/facebook/react-native
- “What Is Flutter, and Why It Seems like the Future in App Development?” DNAMIC, https://dnamic.ai/blog/what-is-flutter/
- Flutter. “Flutter.” GitHub, https://github.com/flutter/flutter
- Ionic. “Ionic Framework.” Ionic , https://ionicframework.com/docs
- Ionic-Team.“Ionic-Framework.” GitHub, https://github.com/ionic-team/ionic-framework
- Matt Netkow. “Ionic vs Flutter: Best Platform for Hybrid App Development.” Ionic , 25 Oct. 2021, https://ionic.io/resources/articles/ionic-vs-flutter-comparison-guide
- Sandip Patel . “Ionic, Flutter, and React Native: When to Use Them .” DZone, 21 May 2021, https://dzone.com/articles/what-are-ionic-flutter-amp-react-native-when-to-us