Mobile development mostly deals with 2 platforms: iOS and Android. There are distinct ecosystems for both platforms — each has its own languages (Java and Kotlin for Android, Objective-C, and Swift for iOS), its own standard environment (Android Studio for Android, Xcode for iOS), its own app architectures, app stores, libraries, etc. The basic capabilities of each platform are similar, and the developer has to consider a lot of the same issues (screen size, obtaining permission for things like location data, etc.), but developing apps for each are distinct processes. Developing native apps for either platform is a lot like developing a native desktop app, which means it’s generally more complex than developing a web app.
Most app developers want to serve the widest audience possible, so they want apps on both iOS and Android. Sticking purely with native development will give you the leanest, fastest apps, but it also means creating and maintaining two entirely different versions of an application. That is, not surprisingly, a pain. Quite a few frameworks have been developed over the years that try to let developers share most of a single codebase between the platforms: Phonegap, Xamarin, Ionic, React Native, NativeScript, and Flutter, just to name a few. These tools try to abstract away much of the native side of development, letting developers work in a higher-level environment, generally something closer to a web-development experience. Some, like Ionic, lean more towards web development; you write a web app that gets wrapped in a native app so it can run on a device. Others, like React Native, lean more towards native development; you use web languages and concepts to write true native applications. In either case, the resulting apps aren’t quite as small or efficient as purely native apps, but they’re pretty good.
A couple of our current projects are using React Native. Much of our web development work has focused on React, and while multiple mobile development systems support React, React Native is probably the most popular in terms of resources, community, and ongoing development.
A React Native app is one part React, one part native iOS app, and one part native Android app. When you use React Native’s command-line tool to start a new app, you get something with some React code and the necessary native code to make the React code run on a device. Ideally, you can write most or even all of the user interface and application logic in React, using standard JavaScript libraries and tools. It’s a lot like web development. You’ll generally still have to use the native tools at some point to build the app, but it’s fairly minimal.
Out of the box, React Native allows developers to create user interface components (windows, buttons, text inputs, all the web things) and interact with some parts of the host device at a high level. For example, React Native lets you check whether a device is using dark mode and change the colors of the status bar icons. It doesn’t give you any low-level access to the filesystem, or let you make in-app purchases, or use the camera. For that, you need third-party libraries, which can include both React and native code.
For simple apps, you’ll barely need to touch the native code. Most react native libraries, for things like in-app purchases or dealing with photo libraries or whatever, will include some native code, but they’ll automatically (mostly) handle wiring things up when you install the library in a project. There’s even a system called Expo, built on React Native, that completely hides the native side of things. When using Expo, you don’t have to use native tooling at all; it’s pretty great (as long as your app doesn’t have to do anything unsupported).
Things get a bit hairier when you want to do things that React Native or third-party libraries don’t support. For example, creating a native keyboard in iOS is a fairly specific thing that React Native doesn’t support (well). When you want to do unsupported things, you have to use native code, at which point you’re essentially writing a native app (although a much smaller one than if you were doing the whole thing natively). At that point, an understanding of how each native environment works starts to become really useful.
Aside from having to deal with React and potentially two native codebases, a developer will also need to understand whatever libraries are being used in the app, and whatever external systems the app has to deal with, some of which can be pretty complex (this isn’t a React Native-specific concern). For example, there’s a React Native library that provides a reasonable lowest-common-denominator API for interacting with both Google and Apple payment systems. That simplifies the process of initiating a payment and seeing what a user has purchased before. However, a developer will still have to have a reasonable understanding of how each payment system works, what setup is required, how to deal with refunds and errors, etc.
So basically, React Native lets you share code and saves you from having to know a lot about native development unless you have to do things outside of React Native, at which point you have to understand native development and React Native — but at least you get to write most of your app code in React. Any questions? 😄