React Native provides an excellent bridge to use native code for functionality that isn't available via JavaScript. In this guide, we'll explore how to write and integrate native modules for Android and iOS, along with detailed insights into their working and best practices.
Why Use Native Code?
While React Native covers most use cases, there are scenarios where you may need to write native code, such as:
- Accessing platform-specific APIs: For example, interacting with low-level device hardware like Bluetooth or Camera APIs.
- Integrating third-party SDKs: Many SDKs only provide native libraries.
- Performance optimizations: Offloading intensive computations to native code for better performance.
By bridging the gap between JavaScript and native languages, React Native enables developers to build truly hybrid apps that harness the best of both worlds.
How React Native's Bridge Works
React Native operates through a bridge mechanism. This bridge facilitates communication between the JavaScript code and the native code. Here’s how it works:
- JavaScript Layer: Handles the UI logic and event handling.
- Native Modules: Perform platform-specific tasks.
- Bridge: Facilitates asynchronous communication between the two.
This architecture ensures smooth integration but requires careful implementation to avoid performance bottlenecks.
Getting Started
To demonstrate native module integration, we’ll build a module that provides a custom greeting message. This guide assumes you have:
- A working React Native app (e.g., created using
npx react-native init). - Basic knowledge of JavaScript, Java (for Android), and Objective-C/Swift (for iOS).
Adding a Native Module for Android
Step 1: Create a Java Module
Navigate to the android directory of your project, and create a Java class, e.g., GreetingModule.java, in the com/{your_project_name} package.
package com.skyhit;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
public class GreetingModule extends ReactContextBaseJavaModule {
GreetingModule(ReactApplicationContext context) {
super(context);
}
@Override
public String getName() {
return "GreetingModule";
}
@ReactMethod
public void getGreeting(String name, Promise promise) {
try {
String greeting = "Hello, " + name + "! Welcome to React Native.";
promise.resolve(greeting);
} catch (Exception e) {
promise.reject("Error", e);
}
}
}Step 2: Register the Module
In the same package, create GreetingPackage.java.
package com.skyhit;
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 GreetingPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new GreetingModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}Next, update MainApplication.java to include the new package.
import com.skyhit.GreetingPackage;
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new GreetingPackage()
);
}Adding a Native Module for iOS
Step 1: Create a Swift/Objective-C Module
In the ios directory, create a new file GreetingModule.m or GreetingModule.swift in your Xcode project.
Objective-C Implementation
#import <React/RCTBridgeModule.h>
@interface RCTGreetingModule : NSObject <RCTBridgeModule>
@end
@implementation RCTGreetingModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(getGreeting:(NSString *)name resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
NSString *greeting = [NSString stringWithFormat:@"Hello, %@! Welcome to React Native.", name];
resolve(greeting);
}
@endSwift Implementation
import Foundation
@objc(GreetingModule)
class GreetingModule: NSObject {
@objc static func requiresMainQueueSetup() -> Bool {
return false
}
@objc func getGreeting(_ name: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
let greeting = "Hello, \(name)! Welcome to React Native."
resolve(greeting)
}
}Step 2: Register the Module
For Swift modules, ensure the bridging header (Bridging-Header.h) includes:
#import <React/RCTBridgeModule.h>Check that your module is exposed in the Xcode project settings.
Using the Native Module in JavaScript
- Create a JavaScript file, e.g.,
GreetingModule.js.
import { NativeModules } from "react-native"
const { GreetingModule } = NativeModules
export const getGreeting = async (name) => {
try {
const greeting = await GreetingModule.getGreeting(name)
return greeting
} catch (error) {
console.error(error)
}
}- Use the module in your app.
import React, { useState } from "react"
import { View, Text, Button } from "react-native"
import { getGreeting } from "./GreetingModule"
const App = () => {
const [greeting, setGreeting] = useState("")
const fetchGreeting = async () => {
const result = await getGreeting("SKYHIT")
setGreeting(result)
}
return (
<View style={{ padding: 20 }}>
<Text>{greeting}</Text>
<Button title="Get Greeting" onPress={fetchGreeting} />
</View>
)
}
export default AppBest Practices for Native Modules
- Error Handling: Ensure robust error handling to avoid app crashes.
- Testing: Test native modules thoroughly on both platforms.
- Performance: Optimize native code to minimize overhead.
- Documentation: Document your native module APIs clearly for your team.
Conclusion
Native modules empower you to extend React Native's capabilities. By following this guide, you can start integrating custom native features into your apps. Experiment with more advanced functionalities and unlock the true potential of hybrid development!




