This month, Bob starts a new series that looks at mobile app development for embedded engineers. We will look at how embedded systems designers can create mobile apps to run on both iOS and Android devices. This month he will introduce two development frameworks: React Native and Flutter.
Over the years at MicroTools, as we developed embedded systems, there was often a need for a mobile app to provide for the human-machine interface to a headless embedded device. One of the first such projects we designed was the Arterial Interface Device (AID) (Figure 1). An AID [1] expands and contracts a balloon blood pump inside the heart in synch with the heartbeat to provide up to 30% more blood flow. The system consisted of: the balloon in the left aorta; an embedded Skin Interface Device (SID) in the patient’s body, much like a pacemaker implant, that provides information about the pumping of the heart and blood pressure; a wearable computer-controlled pump, the NuPulseCV Drive Unit (NDU), to fill the balloon based on inputs from the SID; and an iPad (tablet) that provides the doctor’s interface to the system.
The iPad app allowed the doctor to observe how the patient’s heart was functioning with the implanted balloon pump, and to tweak configuration parameters. We designed the hardware and software for the SID, the software for the NDU, and the software for the tablet. We were so inexperienced with mobile app development that we implemented the iPad app as a browser-based interface written in JavaScript. It worked fine, but it was a challenge to provide real-time ECG graphics. Thankfully, with good buffering, we were able to provide a smooth ECG with only a slight real-time delay. It would have been easier in a true mobile app. Figure 2 shows a screenshot of the app.
We also built a mobile app that interfaced with a fuel cell power generator for a submersible. The app connected with the controller over Wi-Fi and provided real-time data on each of the cells, as well as the ability to tweak the configuration. Again, we chose to design with a JavaScript browser-based interface. In this case, the real-time constraints were not as critical as the real-time graphics of the heart.
Another app that we prototyped, but did not take to production, was used to pace a swimmer practicing in a pool. At the bottom of each lane was a strip of LEDs that would act as the pacer car on a race track. The swimmer would attempt to swim at the pace of the LED light pattern moving at the bottom of the pool. The user would configure on their phone the lap time they wished to achieve. The app, in turn, would communicate over Bluetooth to the LED strip. We did this as an Android-only app because we were familiar with Java (used in Android apps along with Kotlin) but not Swift or Objective-C (used to write iOS apps).
Options for App Development
Prior to 2015, the options for true app development were Java (Kotlin came in 2017), Objective-C, and Swift. All were powerful tools with powerful integrated development environments (Android Studio and Xcode). But Meta (at that time Facebook) realized that they needed a single code base for developing mobile apps. They created a framework called React Native that allowed you to write once and deploy your code on both platforms. There was already the complication of a large number of screen sizes and a vast number of different devices. Today there are over 13,000 different Android devices that an app has to run on. Although there are far fewer iOS devices, the task is still daunting. Meta released their code as open-source and solved both problems, and the world of app development was never the same.
Not to be outdone, Google released a framework in December 2018 called Flutter, which allows developers to have a single code base for browsers, Android, iOS, Windows, and macOS.
The success of both frameworks depended on their performance compared to native apps written in Java/Kotlin and Objective-C/Swift. Both added a layer on top of native code, which was going to affect performance. For the most part, they’ve succeeded. Generally, Flutter is considered faster than React Native, but there are variations based on your exact needs. Although Flutter was late to the game, a 2023 Stack Overflow survey of 23,000 mobile developers showed that 46% of them use Flutter, while 35% use React Native [2]. We’ll have a more detailed comparison later in this series. For now, just know that both are widely used and have a vast array of open-source components (React Native) and widgets (Flutter) to choose from.
In 2022, when I decided to develop an app to run on both Android and iOS mobile devices, I knew that I didn’t want to learn Swift or Kotlin. Nor did I want to go back and re-learn Java. And a single code base was critical. My app was not going to do intense processing, and it didn’t need animation or real-time graphics, so I wasn’t worried about performance. I looked to evaluate both Flutter and React Native as the framework of choice. Let’s take a brief, closer look at these two frameworks.
But first, React
React Native code uses a slightly modified syntax to JavaScript, JavaScript XML (JSX). In Listing 1, you will see the XML-like structures in yellow highlights. It also allows you to use HTML-like structures in your code, (aqua highlights in Listing 1). Knowing JavaScript is a major prerequisite for React Native development.
LISTING 1
Hello World in React
const MyButton = ({text}) => { return ( <button> {text} </button> );}const Salutation = ({text}) => { return ( <div className=”salute”> <h1>{text}</h1> </div> );};export default function MyApp() { return ( <div> <Salutation text=”Hello World”/> <MyButton text = “My Button”/> </div> );}
React Native is also heavily dependent upon the React framework. When I first talked to a developer about an app that he created, he told me to spend a month getting familiar with React before launching into React Native. I didn’t, and probably spent several weeks correcting my misunderstandings of React in my React Native app. So, we should first discuss React.
Created by a software engineer at Meta (then Facebook) as an open-source library for developing user interfaces for the web (somewhat like JQueryUI [5]), React is now maintained by Meta and a community of developers. The two key ideas brought from React into React Native are components and hooks. There is obviously more to it than that. But remember, this is Embedded in Thin Slices!
Components: In React (and thus also in React Native, and so throughout the rest of this section), components are modular and re-usable. You can create new components by inheriting the features of another component. Because of the inheritance capabilities, React projects usually consist of many layers of components. Take a button, for example. You can create a button component with a certain default behavior and pass what are called props (properties) to it, like the text to be displayed, the color, or a function to call when the button is pressed. Then, you can create another button component that inherits everything from your basic button.
Listing 1 uses the two components Salutation and MyButton to display the ubiquitous “Hello World.” Each takes a prop called text.
Hooks: Hooks are another feature of React that become part of the backbone of a React Native app. Hooks are a bit of a catch-all term for components that allow access to the states of your app. The three I used most often are useState, useRef and useEffect:
- useState is used when you want to store a state variable in a component. This is most useful to control the rendering of your component. If something changes within the component and you want to re-render the component, you would update a state variable and the component will re-render.
- useRef creates a variable that is sticky across renderings of your component.
- useEffect is used when you want to connect a component to an external object. For example, if you are playing audio and the audio player sets a variable when the track ends, a useEffect hook can execute some code when that variable changes.
There is much more we can talk about which we will get into in the future, but we have laid enough groundwork now to discuss React Native.
React Native
As in any project, one of the first things you must do is set up the development environment. There are two basic choices: Use the Command Line Interface (React Native CLI), which requires Xcode and Android Studio; or Expo. Given that Xcode only runs on macOS and I didn’t own a macOS device, Expo was my path of choice. I have not regretted this decision. Expo makes so many complicated tasks easier—especially when it comes to submitting your app to the Play Store (Android) and the App Store (iOS).
The downside of Expo is that you cannot add your own native code like you can with the React Native CLI. However, as I needed to do with a Bluetooth interface, you can still use Expo with an existing library that has native code as I did. Expo only has a CLI, so the commands are many and not easy for my brain to remember. But using the recall key in the PowerShell helps me immensely for tasks I repeat often (and can never remember).
There are a host of packages available for your development that extend React Native. Both Flutter and React Native have over 200,000 GitHub entries, so there are plenty of examples and plenty of components/widgets to make life simpler. However, the sheer volume tends to make life more complicated. We will talk about more of them in our next article.
Listing 2 once again has our favorite Hello World to get us started. Note the similarity to React. Also note: this is really all you need to create an app that will run on over 13,000 different Android devices and all of the currently supported iOS devices. The App Store does not accept anything running less than iOS version 13.
LISTING 2
React Native Hello World
import React from ‘react’;import { Text, StyleSheet, View } from ‘react-native’;const YourApp = () => { return ( <View style={{ flex: 1, justifyContent: ‘center’, alignItems: ‘center’, }}> <Text style={styles.myText}> Hello Circuit Cellar </Text> </View> );};const styles = StyleSheet.create({ myText: { fontSize: 30, fontWeight: “bold”, color: “red”, },});export default YourApp;
With Expo, you can load it on a real Android or iOS device. If you have Xcode, you can load it on an iOS simulator, and if you have Android Studio you can load it on an Android simulator.
Again, the yellow highlight text in Listing 2 indicates the required import of the React library. Below that, in aqua, are three built-in components: Text, StyleSheet, and View. The name of your app is (duh) YourApp (light gray). Although React Native does not use Cascading Style Sheets (CSS), it uses something that closely follows in name and function (although the slight differences can be maddening). You can inline your style parameters (lime green) or create your own style sheets (black).
Let me mention one other thing. With Expo development, there is an app called Snack in which you can run and test out portions of your code in an already-built environment. I found this useful when I was getting started and learning the syntax. Figure 3 shows our Hello World running on my phone.
Flutter
We won’t go into as much detail with Flutter at this point. Let’s just start with a little background. Flutter apps are written in a language called Dart. Dart was created by two Google engineers and can be used for web, mobile, or even desktop applications. It has a C-style syntax with Java-like garbage collection to prevent memory fragmentation. It also supports C++-like classes to make it object-oriented. For an IDE, you can use Visual Studio code with Flutter extensions, or Xcode or Android Studio.
LISTING 3
Dart Hello World
import ‘package:flutter/material.dart’; void main() { runApp(const CircuitCellar());} class CircuitCellar extends StatelessWidget { const CircuitCellar({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const MaterialApp( home: Center(child: Text(‘Hello World’)), ); }}
All Flutter code is built around widgets. Every element on a screen is a widget. Using the pre-defined widgets, you can build custom widgets. We will discuss all of this in a later article. For now, take a look at Listing 3, which, once again, is Hello World. Figure 4 shows our Hello World on a mobile phone. If it doesn’t look much like a phone app, don’t worry—we are just getting started with Flutter. By default, it takes over the whole screen.
The import statement in Listing 3 brings in what you need from Flutter’s ecosystem, much like the React import in Listing 2. We have created a custom class called CircuitCellar from the predefined StatelessWidget. build is somewhat analogous to render in React Native. MaterialApp is the core widget of our app, and comes from our import. @override is used to handle polymorphism as used in C++ when one class inherits or is extended from a superclass. It tells the compiler: Yes, I really want to override the default Build function.
Conclusion
And if that doesn’t confuse you, I would be surprised. The main thing I wanted you to see is that React Native is built on HTML, XML, CSS, and Javascript nomenclature and paradigms that are familiar to many of us—even us embedded engineers! Dart will introduce all of us to a new paradigm and new terms. Dipping my toe into mobile app development, I decided to minimize the number of things I needed to learn and went with React Native. In a future article, I’ll show why Flutter will continue to take market share. With either React Native or Flutter, we can truly have a single code base with a single learning curve and create powerful user interfaces on mobile devices for our headless embedded devices. We will dig a little deeper into React Native next time. But of course, only in thin slices.
RESOURCES
Dart | dart.dev
Expo | expo.dev
Flutter | flutter.dev
React | react.dev
React Native | reactnative.dev
REFERENCES
[1] NuPulse—“What is iVAS?”: https://www.nupulsecv.com/technology/
[2] Stack Overflow 2023 Developer Survey: https://survey.stackoverflow.co/2023/
[3] JQueryUI: https://jqueryui.com/
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • APRIL 2024 #405 – Get a PDF of the issue
Sponsor this Article
Bob Japenga has been designing embedded systems since 1973. From 1988 - 2020, Bob led a small engineering firm specializing in creating a variety of real-time embedded systems. Bob has been awarded 11 patents in many areas of embedded systems and motion control. Now retired, he enjoys building electronic projects with his grandchildren. You can reach him at
Bob@ListeningToGod.org





