Moving Cordova plugins to React-Native
(Wait… do we even need them in the first place?)
@ TripCase a good portion of our current work constitutes Cordova plugins. These plugins are used to communicate with the native framework to perform operations, and feed back the results to JS side. With React-Native migration, much time was spent trying to analyze how these Cordova plugins were going to play in the new ecosystem. First look, We thought we would either have to find a way to port the plugins over completely or get rid of them completely and worry about rewriting them all over again. But when we actually began assessing all of the plugins, we drew some interesting findings/conclusions.
Out of all the plugins:
Approximately 70% plugins found their replacements either in React Native as in built option or as an open source library already out there. (which seemed ok since we didn't have to overwhelm ourselves with the fact that we had to rewrite all of the plugins at the very beginning of migration)About 15% were no longer needed since they were essentially the backbone plugin of Cordova itself.The remaining 15% plugins were a concern because:- They were plugins specific to TripCase.- Even though its React counterpart is available, its considered unsafe to replace the plugin right away because of additional functionality it offered.
This meant, we keep the remaining 15% of the plugins as it is for now, find ways to communicate with it and extract results until we rewrite it the good way in future. We came up with two possible solutions after much brainstorming.
- Look for a library that can help bridge Cordova with React Native
- Take just the native files from Cordova plugin → build a react bridge to the native files and tweak the response.
The first one seemed to be the most ideal. In fact we even found a library that offered just that!
https://github.com/axemclion/react-native-cordova-plugin.
Until… we noticed that it offers support only for Android! Bummed by the fact, we let go of that option and looked into option 2. As complex as it sounds, it wasn’t that bad once we actually started to prototype that wrapper. Here’s a gist of what we were trying to achieve.
The JS communicator essentially takes the params from the component. The params include → Plugin class to call, Entry method and the data (if any) that needs to be sent to the plugin.
In order to expose a module from native to JS, react requires that the module be wrapped with RCT_EXPORT_MODULE(); And in order to expose a method, we wrap the method explicitly with RCT_EXPORT_METHOD. The bridge on the native side looked similar to this. (PS: All edge cases are not considered since this was only to prototype the bridging concept for a few plugins).
This ensures that the specified method name gets called and the arguments sent over. sendPluginResultSuccess and sendPluginResultCancelled are observers set up that listen to calls from the native plugin code. In existing Cordova plugins, we ended up replacing
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsString:@”Success”];
[self.commandDelegate sendPluginResult:pluginResult
callbackId:callbackID];
with something like this:
[[NSNotificationCenter defaultCenter]
postNotificationName: @”sendPluginResultSuccess” object: self];
This way we were able to retain the core functionality as it is and only modify the handshake code between the Native and JS side.
Now that doesn’t seem so bad, does it? Feel free to post your questions/opinions/suggestions :)