Bridging Native Modules in React Native: A Comprehensive Guide
React Native Developers can use JavaScript and React to create mobile applications with React Native. But sometimes you need to use native features that React Native doesn’t offer by default. Bridging is useful in this situation. React Native can interact with native code (Objective-C/Swift for iOS and Java for Android) thanks to bridging.
We’ll demonstrate how to create a basic native module for Android and iOS that can be utilized in a React Native application in this tutorial.
Why Use Native Modules?
Certain features must be implemented natively, including:
- Device sensors (accelerometer, gyroscope, etc.)
- Bluetooth access
- File system operations
- Background services
You can make your own native module rather than depending on third-party libraries.
Understanding the Need for Bridging
React Native can interact with native platform code (Swift/Objective-C for iOS, Java for Android) thanks to bridging.
- Accessing device hardware (e.g., sensors, camera, or NFC).
- Implementing performance-critical features.
- Using platform-specific APIs that are not part of React Native.
You can easily incorporate JavaScript into your React Native application by exposing native functionality to it through the creation of a bridge.
Setting Up a Native Module in Android (Java/Kotlin)
Step 1: Setup Your React Native Project
Ensure your project is set up and running. If not, create a new project using:
npx react-native init <Your Project Name>
Step 2: Create the Native Module
- Open the android folder in your React Native project.
- Navigate to android/app/src/main/java/com/yourapp/.
- Create a new Java file named BatteryModule.kt inside com/yourapp.
package com.yourapp
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
class BatteryModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName(): String {
return "BatteryModule"
}
@ReactMethod
fun getBatteryLevel(promise: Promise) {
val ifilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
val batteryStatus = reactApplicationContext.registerReceiver(null, ifilter)
if (batteryStatus != null) {
val level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
val batteryPct = level / scale.toFloat() * 100
promise.resolve(batteryPct)
} else {
promise.reject("ERROR", "Could not get battery level")
}
}
}
Step 3: Register the Module
Create a new Kotlin class BatteryPackage.kt in the same directory that implements the ReactPackage interface. This class registers your native module with React Native.
package com.yourapp
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ViewManager
class BatteryPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(BatteryModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
Step 4: Register on MainApplication.kt
Open android/app/src/main/java/com/yourapp/MainApplication.kt and add the module to getPackages():
override fun getPackages(): List<ReactPackage> {
return listOf(
MainReactPackage(),
BatteryPackage() // Add this line
)
}
Setting Up a Native Module in iOS (Swift)
Let’s create a similar module to get the battery level in iOS.
Step 1: Setup Your React Native Project
Ensure you’ve installed the iOS dependencies using:
cd ios
pod install
Step 2: Create the Native Module
- Open ios/yourapp.xcworkspace in Xcode.
Inside the yourapp folder, create a new Swift file named BatteryModule.swift.
import Foundation
import UIKit
import React
@objc(BatteryModule)
class BatteryModule: NSObject {
@objc static func requiresMainQueueSetup() -> Bool {
return true
}
@objc func getBatteryLevel(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
UIDevice.current.isBatteryMonitoringEnabled = true
let batteryLevel = UIDevice.current.batteryLevel * 100
if batteryLevel >= 0 {
resolve(batteryLevel)
} else {
reject("ERROR", "Could not get battery level", nil)
}
}
}
Step 3: Register the Module (Objective-C Only)
In ios/yourapp/AppDelegate.m, add:
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(BatteryModule, NSObject)
RCT_EXTERN_METHOD(getBatteryLevel:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
@end
Using the Native Module in JavaScript
Step 1: Link the Module
React Native automatically links native modules for iOS using `pod install`.
Step 2: Use Native Module
Now that our native modules are set up, let’s use them in JavaScript.
import { NativeModules } from 'react-native';
const { BatteryModule } = NativeModules;
const getBatteryLevel = async () => {
try {
const level = await BatteryModule.getBatteryLevel();
console.log(`Battery Level: ${level}%`);
} catch (error) {
console.error(error);
}
};
getBatteryLevel();
Conclusion
Well done! You have effectively built a bridge between native iOS and Android code and React Native. When incorporating platform-specific features, native modules offer flexibility, enabling your React Native apps to fully utilize native capabilities.Additional functionality, like retrieving network status, accessing device storage, or integrating third-party SDKs, can be added to this example.
Happy Coding!