React Native interfacing with Native code
Overview
Being new to React Native and coming from a pure native experience I was looking for a starting point of learning React Native. In our use case we are expected to provide a Reference app for our customers who use Hybrid framework like ReactNative in their apps. As such, we are not looking to develop a full blown React Native Application. Instead focus on the JS-Native interface. So, I came up with some questions and started answering them to make interfacing our SDK easier. As such, this page provides these questions and answers. I hope to cover some design aspects to consider while interacting with an SDK. The information provided in this page is based on the results of Studying the react-native bridge for AppAuth SDK and also several other references I linked below.
Please note that, this post does not cover the basics of ReactNative. For that this excellent guide here is a good starting point.
How do we create instances of Custom Classes on JS side?
There are situations where the native interface provides custom classes that are not part of Android or iOS platform. We will have to deal with interacting with these custom classes on JS(JavaScript) side. As such, this problem can be solved 2 ways.
- Use JSON serialization to wrap the properties of a class in a JSON object on JS side and deserialize this JSON object on Native side. This is not a straightforward process and this article here is an excellent reference.
- Pass the fields of the class as individual parameters to a Bridge API and create instances of custom classes on the Bridge layer. This avoids the JSON serialization/deserialization overhead and is a simple but effective approach for most light weight objects that are wrappers around primitive fields. The AppAuthSDK bridge provided here has examples on achieving this with AppAuth Android SDK and AppAuth iOS SDK.
How do we handle Async SDK API?
Create a bridge layer API that abstracts the asynchronous behavior for an async/await
JS calls. This is done using @ReactMethod
annotation on Android side and RCT_REMAP_METHOD
macro usage on iOS side. When we use these annotation/macro helpers React framework passes us an additional Promise object(s) that could be resolved on the native to return the results to JS side. More information on using Asynchronous communication using promises can be found here for Android and here for iOS.
How do we handle Callbacks?
If we prefer not to use async/await
calls on the JS but use pure React flow by using callbacks we can achieve this using some specialized classes provided by the React framework. On the iOS side we could use RCTResponseSenderBlock
to send the response back to JS side from the bridge layer. An example for this kind of communication can be seen here. On the Android side we can use a special React Class called Callback
to send the result back to JS side. An example for this kind of communication can be seen here.
How do we pass standard arguments (Classes provided by Android/iOS Platforms like NSURLRequest) to SDK?
The sample SDK that I have studied does not contain examples of any such usages. The SDK pretty much Serialized all the arguments required by the Native SDK as an array. Across the bridge the types are interpreted on the Native side as mentioned here for Android side and as mentioned here for iOS side. On the iOS side there is a JS method provided by the React Library called as RCTConvert
. The types supported by RCTConvert
are listed here. As can be seen from the list, NSURLRequest is supported by RCTConvert. Another good resource on this subject is here. For this situation I have provided a Gist where I show the code for handling a Map/Dictionary
in JS-Native and Native-JS communication.
How do we handle networking functionality on the app side to reduce Native Bridge Code?
Basically use fetch
JS API provided by React Native. An example can be found here.
How do we standardize development process of the React Native App dealing with Native SDKs?
Here are some of guidelines for development process with React Native App that we felt are needed while interfacing to Native SDKs
- Avoid platform dependent code on JS side as much as possible.
- Make sure all the configuration changes are abstracted on the JS side to avoid building/loading the native layer every time there is a change. This will also increase the speed of development because of the “Hot reload” feature for JS side changes on file save.
- Abstract the SDK/Platform specific complexity on Native Bridge Layer. This will keep the JS layer simple and easy to manage. However, this should not push the business logic to Native side as it will defeat the purpose of having a Hybrid framework.
- Use async/await API on JS side.