Saturday, July 28, 2018

Connecting Native Module with React Native (iOS)

React Native is a very strong and popular framework to create iOS and Android app at the same time with a single code base. The developers do not need to learn two different languages to create multiple apps of the same idea. There are many exciting features of React Native you will enjoy. Among them, the most interesting feature of React Native is, this can be used along with native code (Objective C/Swift or Java).


In this post,  I am gonna show you how to communicate between native code and React Native. First of all, we need to know why do we need to communicate with these two. Suppose you have an existing native code. Now you want to use them in your RN code/project. Either you have to rethink those code in RN style or you can bridge them. Well sometimes rethinking is tough. So it is better to use the bridge procedure. I,n my case I had to implement Estimote SDK in my app which is only available for Objective C and Java (if I am not wrong). So in this case rethinking did not help me.

Now let’s talk about the bridging process. Do not panic. It is a very easy process. Just follow my steps.

First, create a React Native project by react-native init [Project Name] (here I have used bridgeRNiOS). Now go to your project folder. There you will find a folder named “ios”. In that folder you will find the Xcode project (in this case  bridgeRNiOS.xcodeproj). Open it in XCode. (Image 1)

Image 1: Open XCode project
In XCode, under bridgeRNiOS folder create a Cocoa Touch Class. Give any name. (like I gave MyObjectClass). This file is a subclass of NSObject ( You can use ViewController as a subclass. But in this tutorial we are not communicating between UI Components. So it will unnecessary). (Image 2)

Image 2: Creating a customized class


Now open the MyObjectClass.h file. If you see #import <Foundation/Foundation.h> there you can remove it. Then add #import “React/RCTBridgeModule.h”. After doing this add the protocol of RCTBridge. (Image 3)

Image 3: Importing React Bridge Module in Objective C
Come to the MyObjectClass.m. Now we need to add macro, RCT_EXPORT_MODULE(), so that React Native expose the method of MyObjectClass to JavaScript. In Image 4 you can see that the macro is asking an argument. It is optional. If you keep it empty then in JavaScript the module will be accessed by Objective C class name (here MyObjectClass). Confused!? Ok, let’s try with an argument.  Give any name. Let’s say NativeClass. Now we have to export the constant native to JavaScript. To do so add,
-(NSDictionary *)constantsToExport {
return @{@"message": @"Hi Codelady.. I am from the XCode..\n Muhahahahahaaa”};
}
Image 4: Macro asking argument
Do not try to change the name of this, constantsToExport, method. Otherwise, you will face a red alert box. After adding the macro and the export method your class will look like Image 5.

Image 5: Export method with an argument

Now open your App.js file in VSCode. First thing we have to here is to import the Objective C module in our JavaScript file. To do this add
import {NativeModules} from 'react-native';
var MyObjectClass = NativeModules.NativeClass;
Wait a minute at this point. If you notice, I have used NativeClass after NativeModules. The same name I have given to the macro’s argument. In the image 6, you can see the app is running successfully in the simulator. You can test it by changing the name. See the result in image 7. What if we use no argument in the macro? If no argument then just use the Objective C class name after NativeModules like image 8.

Image 6: Importing native module in JS

Image 7: Changed the imported class name
Image 8: Exporting native module when 
no argument is given










Now, let’s see how the constant of the native code can be called in the JavaScript code. In the image 6  you can see in the render function I have displayed the constant by adding {MyObjectClass.message}. Notice that the property of MyObjectClass (message) is the same as the returned object’s key of the Objective C method constantToExport. See, how easily we have passed data from native code to React Native.

What if we have to access a method of native code from React Native? This process is also easy. To do this, first of all in your Objective C class add a macro, RCT_EXPORT_METHOD(), for exporting its' method to JavaScript. In image 9, you can see (in XCode) in this macro there is an event named “sendFullMessage” with two arguments (name and starNumber). This event will print a log message using these two arguments. In the JavaScript file you can call this method simply using:
MyObjectClass.sendFullMessage('Lucas', 4);
Image 9: Accessing Native method from JS
If you notice this sendFullMessage method does not return any value to JavaScript. It is just printing a log message. Due to this reason, the alert message says “undefined” But in real life, we need to get a result. So!? How can we do that right? Do not worry because the native module provides a special argument called “callback”. Add RCTResponseSenderBlock callback as an argument in the event  and in the body add the result you want to callback. In JavaScript (App.js) file add the following snippet, 
MyObjectClass.sendFullMessage('Lucas', 4, (error, msg) => {
 if (error) {
   console.error(error);
 }else {
   alert(msg)
 }
})
You can see the whole process In image 10. Notice the alert is not saying “undefined” now.
Image 10 : Returning value from Native module to JS
Image 11 is showing, if you have a separate method in Objective C and you have to access its return value by the callback.
Image 11: Calling a separate method Native Module


Hopefully, I have covered all the point you will need to bridge native code to React Native. Still, if you have any question then please let know. I will gladly try to help you.  

No comments:

Post a Comment