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.
While React Native covers most use cases, there are scenarios where you may need to write native code, such as:
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.
React Native operates through a bridge mechanism. This bridge facilitates communication between the JavaScript code and the native code. Here’s how it works:
This architecture ensures smooth integration but requires careful implementation to avoid performance bottlenecks.
To demonstrate native module integration, we’ll build a module that provides a custom greeting message. This guide assumes you have:
npx react-native init
).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);
}
}
}
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()
);
}
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);
}
@end
Swift 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)
}
}
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.
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)
}
}
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 App
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!