Our current WorkSimple app in production is a Cordova hybrid app which means that our UI is web based. We are putting in a lot of effort trying to make the user experience as smooth as possible, but it never feels as good as native apps.
For this reason, we have been pushing for React Native for a while. Once we received the go-ahead we decided that our first milestone would be to get rid of Cordova and its plugins but stay inside the WebView running within a React Native wrapper, and in the next milestone we plan on migrating our app’s React.js components to React Native.
We are happy to share some of what we have learned during the process, with a focus on working with the React Native WebView.
The first and most basic task we had was to find a way to communicate between the React Native code and the web code running in the WebView. There are three React Native WebView APIs that can be used (not including some more ways that require writing native code):
The problem is that this code will only run once the WebView is loaded so unless you want to reload your web content each time you want to pass something into the WebView this is not the way to go. This would be more suitable for some one time onLoad code.
Sending messages between React Native and the WebView is a matter of calling postMessage and implementing onMessage on the receiving side to get the message:
This seems simple enough, but if you’re planning on heavy usage of this communication channel you should be aware of a few caveats:
- There is no out of the box response mechanism for the postMessage calls (on both sides) so you would probably need to have some components that can manage some sort of callback mechanism. You can take a look at the WebViewBridge example for a sample implementation of such a component for the code running in the WebView.
- There is an issue in iOS when doing consecutive window.postMessage calls. The way React-Native implemented the window.postMessage in iOS is by setting a URL with a special schema and containing the data posted as a url parameter. Then in the native code, they listen for url changes and look for ones with the postMessage schema to extract the data and pass it to the onMessage handlers. The problem is that doing consecutive window.postMessage calls in iOS will result in losing your first calls as the url is overridden each time before the message is delivered so the last call wins. Luckily, a fix for this issue is on its way. In the mean time, you can checkout the WebViewBridge sample which handles this issue with a promise chain that resolves each time a message gets delivered.
Another concern we initially had with the implementation on iOS was that since the data is actually posted on the url string, can it handle large data? We tested this by passing a 20MB image file encoded as a base64 string — turns out iOS has no problem passing that successfully.
But be careful, do not do this in debug mode. When we accidentally logged the url containing this massive string to the console, the app froze up entirely — our guess is that since it is transmitted over a websocket to the chrome browser, the debug channel gets jammed.
As of now we’ve completely replaced all of the Cordova code with React Native, still utilizing a WebView to host our app. The choice of using postMessage/onMessage for communicating between React Native and the WebView has turned out to work quite well.
Update 1: A question that keeps coming up from people who read the post is :”Did you get a big performance boost?”
Well getting the big performance boost wasn’t the goal of the our first mile stone in the migration to React-Native (since most of our UI & logic still live inside the WebView). If you take into account that in our pure Cordova app, calls to native used to go over the WebView bridge straight into the native code where in our current state in our React-Native app calls go over the WebView bridge and then probably (if native code is needed) over the React-Native bridge as well. So we might even experience some performance degradation at this stage.
But the Cordova FW and plugins are huge and not having to load all that code and wait for device ready did give us an improvement in load time.
Update 2: React Native 0.57 moves to WKWebView!