Native module in React-Native

Fatema Patel 2021-06-15

Objective

Sometimes we need to communicate between React Native and native bridge. we have to access the native platform's APIs that are not available in Javascript. These can be done by creating a native module in react-native.

Sometimes we need to communicate in between React Native and native bridge. we have to access the native platform's APIs that are not available in Javascript. If an application needs to access some native modules and there is no npm module available. It can be done by creating a simple setup of a native module. React Native methods can also be invoked from Native modules.

The Native Module system allows us to use native APIs code written in Java, Kotlin, Objective-C, and Swift with JS code. Native module works as a bridge between native APIs and React Native code, allowing us to run native APIs code within JS, send data to native APIs, and receive data from native APIs.

In this article, we will build the architecture to implement native modules in React Native.

1. Create a React Native Project

To  create one, run the command in the terminal:

react-native init NativeModuleDemo

2. Creating Native Module

Creating Native Module (iOS)

We will integrate the native module in iOS first. Your React Native project should have 'ios' and  'android' folders in the react-native project directory. Let’s open the iOS project workspace in Xcode.

For this article we will write native code in Swift, so let's begin by creating a swift file in Xcode in your project.

Let’s name it 'ToastModule', we can name it whatever we want. When we have the swift file, it will prompt you to create a bridging-header file, so you need to select the 'Create Bridging Header' option. XCode creates the bridging file for code communication between Objective-C & swift.

Let’s add a header line in Bridging-Header.h file.

#import "React/RCTBridgeModule.h

Native Module Class

Since we have created ToastModule file, let’s add native code in it for communication with React Native code. Whatever class we want to communicate with react-native, We have to import RCTBridgeModule to use the macros for native and react-native code bridging.

NativeModuleManager will look something like this:

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

NS_ASSUME_NONNULL_BEGIN

@interface ToastModule : NSObject<RCTBridgeModule>

@end

NS_ASSUME_NONNULL_END

Exposing Native Modules

We have implemented the class that will communicate with React Native, but haven’t exposed the class to React Native yet. So now we expose the code using Obj-C macros provided by React Native.

To use a macro, we will create a new objective-c class and name the file 'NativeModuleManager.m'.

#import "ToastModule.h"
#import <React/RCTLog.h>

@implementation ToastModule
RCT_EXPORT_MODULE(Toast);

RCT_EXPORT_METHOD(show)
{
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Native Test" message:@"Message from Native Module" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
  [alert show];
}
@end

RCT_EXTERN_MODULE macro is used to expose the native class to react-native, the first argument is the name of a class that we want to expose to react-native and the second argument is the superclass.

RCT_EXTERN_METHOD  macro is used to expose any methods in a native module to JavaScript. In order to pass a result from a RCT_EXTERN_METHOD method to JavaScript you can use callbacks or emit events.

Creating Native Module (Android)

The next major step is integrating the native module into Android.

Your react-native project should have an 'android' folder in the react-native project directory. Let’s open the android project in Android Studio.

Native Module Class

Now it's time to implement the getName method in the class that we want to expose to react-native. This method returns a string, which represents the name of the native module.

NativeModuleManager will look something like this:

package com.nativeModuleDemo;

import android.widget.Toast;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.util.HashMap;
import java.util.Map;

public class ToastModule extends ReactContextBaseJavaModule {

    public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "Toast";
    }

    @ReactMethod
    public void show() {
        Toast.makeText(getReactApplicationContext(), "Toast from Native Code", 
        Toast.LENGTH_SHORT).show();
    }
}

Registering Native Modules

We have to register the native module with react-native in android. We will add native modules to ReactPackage and then register the ReactPackage with React Native.

During initialization, react-native iterates overall packages, and for each ReactPackage, it registers the native module.

For Android, to access the native module in react-native, we will instantiate and return it with the createNativeModules method.

To add native modules to react-native, let’s create a new class named 'ModuleManager '. We will implement ReactPackage in this file which will expose our native code to react-native.

ModuleManager will look something like this:

package com.nativeModuleDemo;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ModuleManager implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new ToastModule(reactContext));

        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

For registering the ModuleManager, we have to add code in MainApplication.java as well. The `MainApplication` is where we will add our package class which contains a list of native modules.

 @Override
 protected List<ReactPackage> getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List<ReactPackage> packages = new PackageList(this).getPackages();
  // Packages that cannot be autolinked yet can be added manually here, for example:
     packages.add(new ModuleManager());
     return packages;
   }

Accessing Native Modules

We have set up basic things in the iOS project, now let’s move to the react-native project for consuming native code.

Consuming the native module is the simplest thing, we just have to import NativeModules from react-native. All our exposed code would be accessible in React native.

In App.js let’s import NativeModules and console it, to check whether the exposed code is accessible here.

import {NativeModules, SafeAreaView, Button} from 'react-native';

const Toast = NativeModules.Toast;

const App = () => {
  return (
    <SafeAreaView>
      <Button title={'Check Native Event'} onPress={() => Toast.show()} />
    </SafeAreaView>
  );
};

export default App;

 

Summary

Implementing native modules in both the android and iOS projects add great value to the React Native ecosystem, as we have a grip on native APIs while maintaining a single codebase for android/iOS platforms.

Created on : 2021-06-15
Written by

Fatema Patel

Jr. React Native Developer

Tags
React-native
Native-Component
native module
ios-native-module
android-native-module