paint-brush
Understanding the React Native bridge conceptby@mfrachet
63,434 reads
63,434 reads

Understanding the React Native bridge concept

by Marvin FrachetNovember 10th, 2017
Read on Terminal Reader
Read this story w/o Javascript

Too Long; Didn't Read

And why its architecture is awesome, at a top level.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Understanding the React Native bridge concept
Marvin Frachet HackerNoon profile picture

And why its architecture is awesome, at a top level.

React Native is often presented as a game changer that allows to run JavaScript code inside a mobile environment. Its main strength is that it doesn’t rely on webviews like other competitors (Phonegap, Ionic, Cordova…), but on the actual real materials provided by the different platforms. It has built-in access to all the native views and components, and to about 70 specific device APIs by default (you can extend it).

When writing React Native apps, we build native UIs. And that’s the key point, we create UIView instances just like we would have with platform specific languages:

RCTView implements UIView

My first assumption on this framework was something like:

They probably create an AST from the JS code and transform it to make it run on multiple devices.

That would make sense and that’s actually what Google/Flutter does while building apps (with Dartlang). But that’s not the React Native way.

The main problem with this approach is that targeting platforms for compilation based on JavaScript code would imply the creation of new compilers. I don’t know any existing tool accepting JavaScript as entry code that is able to produce code for every targeted platform (eventuall see Jasonette).

NB: some have tried but only for mobile development with opinionated approaches

But what currently exist are compilers that target their own specific platform. For example, we have compilers that accept Java / Kotlin code and target Android platform, or Obj-C / Swift targeting iOS platform. It exists many compilers for different languages and targets. They do their job well because they have been designed to create optimised artefacts for them.

React Native is built in such a way that it uses existing compilers:

It’s built with a really opened architecture that allows the code to be run, not only on mobile devices, but also on other platforms:

It can also be used with other frameworks:

So how did the team build such a framework, that is platform and framework agnostic, by using the existing tools & compilers?

Multiple realms interacting, nothing else

Let’s take a step back and look at the big picture of React Native.

React Native deals with two realms, the JavaScript one and the Native one. Both of them are able to share information. They communicate using a “bridge”, which is definitely the very heart of the React Native architecture, the part that offers so much flexibility.

The bridge is the concept that provides a way for bidirectional and asynchronous communications between these two universes. What’s important here is that they are completely written in different technologies, but they are able to communicate.

JS threads communicates with the native ones through the bridge

Remember your backend side

Let’s remember when we were coding distributed backend applications with multi-service communications.

How do we manage communication between two services that are completely different at a language/platform level ?

We used interoperable languages, such as JSON or XML, and we relied on asynchronous protocols such as AMQP (or any other).

Bidirectional communications between heterogeneous services

If we want these two services to communicate, we rely on a message queue. The first service pushes some commands inside the queue and the other one has to execute these commands when possible.

React Native behaves the same way. The JavaScript realm sends asynchronous JSON messages describing the action the Native part is supposed to accomplish.

For example, the JavaScript side will send information concerning the views that must be created by the Native side. When the Native side is ready, it will effectively create the views:

JavaScript sends commands asynchronously to the Native side for view management, with JSON

In React Native, the bridge endorses the message broker role, handling asynchronous commands between the two different worlds.

It offers multiple possibilities:

  • since it’s asynchronous, it’s non blocking, and therefore allows for smooth view management on the screen (~6O fps is the React Native golden goal)
  • since it’s decoupled and based on interoperable languages, it’s wide open to other frameworks and rendering systems provided that they respect the React Native bridge command interface

The more the bridge’s language is ubiquitous and universal, the more the possibilities are… and it is indeed!

The bridge implementation

The bridge is built in C/C++ and thus, can be run on multiple platforms, OS etc...

It embeds the Apple JavaScriptCore framework in, which exposes APIs to access the actual JavacriptCore VM capabilities. Many people use these APIs on the Obj-C and Swift world. But there is a C API, and the Obj-C one is actually just a wrapper.

With this in mind, JavaScript code can be run inside a C/C++ program. It can inject variables, functions and declare globals to enhance the JavaScript existing code. React Native relies on this kind of magic to make JavaScript communicate with the native world and thus trigger actions in the C/C++ world.

Injecting stuff inside the JavaScript code also means that functions can be executed by the C/C++ code.

This diagram quickly sums up how the JavaScript world is able to deal with the C/C++ one:

The JS code is managed by the JSCore framework

The native side

The communication on the native side is “the easiest” part.

Let’s begin with the iOS platform. Since Obj-C is an extension of the C language, it can communicate with it natively. This way, exchanges between the bridge and the Swift / Obj-C world are easy and natural.

High level diagram of JS interacting with iOS world

On Android, we need to rely on the Java Native Interface to dialog with the bridge.

High level diagram of JS interacting with Android world

Here’s an old but really awesome and deep post explaining how the bridge is implemented on iOS by Tadeu Zagallo.

Let me know if you have further questions regarding React Native internals. I’ll try to provide all that I know on the topic.

Thanks to my mates @Zenika and @M6Web for the reviews !