Why React Native needs C++How bridging to lower level languages allows us to write both our view, business and performance critical code only once.
Rudi YardleyBlockedUnblockFollowFollowingJan 6Mobile development is inherently a multi-lingual enterprise.
Usually this means writing the same functionality in multiple languages.
In this series I want to explore an interesting technique for simplifying our codebase by utilising the power of C++ to achieve more maintainable cross platform development.
Chances are the polyglot reality of mobile development will leave you in for quite a surprise.
That was certainly the case for me as I attempted to get cross platform audio processing to work with React Native for a recent project.
So after much study and mucking about getting it working I thought I would share the process for the benefit of folks coming to React Native from a web development background.
Mobile development is a polyglot enterprise and will likely continue to be so while major players compete for platform dominance.
Evidence can be found in the failure of bridging projects such as React Native and Cordova from shielding us from this reality.
Why reach for native codeDue to the tendency for app developers to gravitate towards novel ideas, as well as the attempt to squeeze more and more performance from those little mobile processors, it’s likely you‘ll find the corners of the React Native ecosystem somewhat lacking and eventually be forced off the beaten track to bust out a custom native component or two.
This can happen for all sorts of reasons but generally React Native is pretty good at handling UI so these days breaking out to native would likely be for algorithmic performance-critical behaviour such as image, audio and video processing, machine learning, 3D graphics or facial detection amongst other things.
You may also find yourself in a situation as a React Native developer where in order to tailor components to your needs, you must customise components you already use.
That too can often mean making the leap to native platforms.
Don’t repeat yourselfNow whilst it’s ok for mobile development to be inherently polyglot, if the component is complex enough (and most of the above example are) then the thought of coding functionality twice for both platforms alongside the associated maintenance costs should rightfully make your hair stand up on end!Thus, it is important to find a solution to the maintenance problems created when native code diverges, but how can we provide performant code for both platforms without having to rewrite everything twice?Ideally what we need is a way to code all our high performance app components once and only once.
In reality there will be times we must take advantage of platform specific functionality in native languages, but for complex performance sensitive advanced functionality, we can avoid overhead by settling for a third option.
Searching for a ‘lingua franca’ of computersThere are a few ways to solve this problem.
As you can tell from the title of this article I settled on C++ because of my needs but you may find other techniques work for your project.
For example, you may want to look into Kotlin Native which can compile Kotlin for iOS targets, which is a perfectly valid solution to the problem.
Alternatively, you might be able to make some headway by compiling Rust or another similar language to Web Assembly then shipping that with your app however the non-natural wasm execution environment could limit your ability to use 3rd party libraries.
In my case, I wanted to work with performance critical audio processing libraries and unfortunately pretty much every serious audio lib out there is written in cold hard C++.
Nevertheless, it turns out that one thing just about all computer systems have in common in that they can act as a compilation target for C and C++ and both Android and iOS are certainly no exception.
It might surprise you coming from web development that bridging to C++ is actually a common approach to shared code in mobile development outside the React Native space.
Dropbox have actually been doing it for years now for their shared business logic.
Modern C++ is actually pretty approachableTo be honest I had not looked at C++ since attempting and failing to create VST plugins around 20 years ago.
Initially the thought of using it filled be with as much joy as going to the dentist or doing my taxes.
However through the lens of two decades of professional programming experience, I began to notice modern C++ is actually not as tough as I expected.
There are newer features that help with some of the harder elements of the language such as smart pointers for memory management.
I find it easier and more intuitive than approaching Haskell for example however things do still get complex quickly in some cases.
If you need a video primer I highly recommend Cherno’s tutorials on youtube.
Lost in translationNevertheless, getting native systems talking to C++ is more difficult than I expected.
It becomes apparent rather quickly there is a tonne of indirection when attempting to access one language from another on mobile systems.
React Native provides a mechanism to access Objective-C on iOS and Java on Android which gets us native execution, but that is only the easy part of the challenge.
Because they share the same C-based memory model, things turn out to be ok-ish when moving from Objective-C to C++.
We can reference C++ objects using Objective-C++ (a hybrid language that shares constructs from Objective-C and C++).
However by nature as a hybrid language Objective-C++ can accommodate 2 types of exceptions, 2 types of ref counting and 3 types of bugs*.
So having a lot of logic there is definitely a bad idea.
Basically we want to wrap our calls and get out.
Things get more difficult and disturbing in Java where we are stuck mapping types over JNI which can be extremely tedious and error prone even when doing simple things.
The whole system works using magic method names in the C-language space and every data type needs to be marshalled explicitly and correctly.
Basically there are lots of details and the results will likely be fragile and error prone when building this bridging code by hand.
The Djinni is out of the bottleLuckily Dropbox had that very same problem a few years ago and came up with a great little open source solution called ‘Djinni’ (pronounced like Genie).
Djinni generates mobile bridging code based on a simple interface definition language that can describe your bridging API.
You might want to checkout dropbox’s introductory video to Djinni.
Djinni sounds like a great solution to sharing C++ code between platforms however scouring the web for tutorials on how to set up Djinni specifically with React Native didn’t bear much fruit apart from a couple of mysterious repositories that generally were out dated and didn’t work when I tried to use them.
In the end I found elements from a handful of tutorials helped me get this working and have successfully been able to get C++ talking to both platforms.
I have referenced them at the bottom of this article.
Broad architecture for nowThis is the broad architecture I am considering for reusable “write once” mobile apps.
As a side note it may be possible to make a Djinni plugin to bake a bridge from React Native directly into C++.
It has been attempted here yet I found the code was custom, out of date, lacked detailed documentation and I did not want to use unsupported code for my purposes.
As I work more with this architecture I will attempt to get the react-native djinni plugin to work since I think it would result in a cleaner architecture and will write about it and update this tutorial but for now I will stick to keeping ReactNativeBridge and Djinni as separate.
Next StepsHopefully I have made the case for how and why it is useful that we can bridge to C++ within the context of React Native.
The rest of this series acts as a guide to implementing cross platform communication with React Native.
In the next instalment we will cover getting React Native talking to both Objective-C and Java as the first step in bridging React Native and C++.
Other articles in this series:Why React Native needs C++Talking like a React NativeMobile to C++ with DjinniConnect React Native to C++This article is a living document please reach out to me if you want to contribute or see anything inaccurate here.
You can follow Rudi Yardley on Twitter as @rudiyardley or on Github as @ryardley.