Logo

Home

Services

Products

Projects

Who We Are

Blogs

Contact Us


Pooja Joshi

6 mins to read

2025-05-22

Building Cross-Platform React Native Bridges for iOS and Android

Connecting React Native with Native Code: A Deep Dive into Bridges

React Native's strength lies in its ability to bridge the gap between JavaScript and native platforms (iOS and Android). This "bridge" facilitates communication, enabling developers to leverage existing native libraries within their React Native applications. This capability is crucial for building production-ready apps with enhanced performance and access to platform-specific features. This article provides a comprehensive guide to creating native bridges that work seamlessly across both iOS and Android, allowing you to harness the power of Swift/Objective-C and Java within your React Native projects.

Building Our Example: The LightApp

To illustrate the concept, we'll build a simple "LightApp" using the react-native CLI. This app will demonstrate how to control a virtual "Bulb" through a native bridge. The same React code will function on both platforms, showcasing the cross-platform nature of this approach.

react-native init LightApp
cd LightApp

The tutorial is divided into two sections:

  • Section 1: Native Bridge in iOS
  • Section 2: Native Bridge in Android

Section 1: Native Bridge in iOS

This section focuses on building a bridge between Swift/Objective-C and your React Native component. The process involves three key steps:

  • Creating the Bulb Class and Bridge Header
  • Addressing GCD Queue Warnings
  • Accessing Variables and Implementing Callbacks

Step 1: Creating the Bulb Class and Bridge Header

First, within Xcode, create a new Swift file named Bulb.swift. Also, create a bridging header file (if one doesn't already exist) named LightApp-Bridging-Header.h. This header file allows communication between Swift and Objective-C. Add the following line to the bridging header:

#import <React/RCTBridgeModule.h>

This import provides the necessary interface for bridging.

Next, update Bulb.swift with the following code:

import Foundation

@objc(Bulb)
class Bulb: NSObject {
@objc static var isOn = false

@objc func turnOn() {
Bulb.isOn = true
print("Bulb is now ON")
}
}

We've created a Bulb class inheriting from NSObject, making it compatible with Objective-C. The @objc annotation exposes the class and the turnOn function to Objective-C and subsequently to React Native.


Now, update App.js to access the Bulb class:

import React, { Component } from 'react';
import { Text, View, NativeModules, TouchableOpacity, StyleSheet } from 'react-native';

export default class App extends Component {
turnOn = () => {
NativeModules.Bulb.turnOn();
};

render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to Light App!!</Text>
<TouchableOpacity onPress={this.turnOn}>
<Text>Turn On</Text>
</TouchableOpacity>
</View>
);
}
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});

Running the app and checking the Xcode console will confirm that the Swift turnOn method is called from JavaScript.


Step 2: Addressing GCD Queue Warnings

You might encounter warnings related to running native code on the wrong thread. To ensure the native module runs on the main queue, add the following to Bulb.swift:

@objc static func requiresMainQueueSetup() -> Bool {
return true
}

Step 3: Accessing Variables and Implementing Callbacks

To display the bulb's status in the app, add a getStatus function to Bulb.swift:

@objc func getStatus(_ callback: RCTResponseSenderBlock) {
callback([NSNull(), Bulb.isOn])
}

This function takes a callback and returns the isOn value. Update App.js to utilize this:

constructor(props) {
super(props);
this.state = { isOn: false };
this.updateStatus();
}

turnOn = () => {
NativeModules.Bulb.turnOn();
this.updateStatus();
};

updateStatus = () => {
NativeModules.Bulb.getStatus((error, isOn) => {
this.setState({ isOn });
});
};

render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to Light App!!</Text>
<TouchableOpacity onPress={this.turnOn}>
<Text>Turn On</Text>
</TouchableOpacity>
<Text>Bulb is {this.state.isOn ? "ON" : "OFF"}</Text>
</View>
);
}

Section 2: Native Bridge in Android

Now, let's create the equivalent functionality for Android. Create a Java class named Bulb.java within the Android project and add the following code:

package com.lightapp; // Replace with your app's package name

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

public class Bulb extends ReactContextBaseJavaModule {
private static boolean isOn = false;

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

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

@ReactMethod
public void turnOn() {
isOn = true;
System.out.println("Bulb is turned ON");
}

@ReactMethod
public void getStatus(Callback successCallback) {
successCallback.invoke(null, isOn);
}
}

Next, create a Java class named BulbPackage.java and add the following code to register the module:

package com.lightapp; // Replace with your app's package name

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 BulbPackage implements ReactPackage {

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

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

modules.add(new Bulb(reactContext));

return modules;
}
}

Finally, you need to register the BulbPackage in your MainApplication.java file. Import your BulbPackage class, and add it to the getPackages method:

// ... other imports

import com.lightapp.BulbPackage; // Import your BulbPackage

public class MainApplication extends Application implements ReactApplication {

// ... existing code ...

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

// ... existing code ...
}

The same JavaScript code used for iOS will work for Android as well, demonstrating the cross-platform compatibility of the bridge.

Conclusion

By following these steps, you can effectively create and utilize React Native bridges, unlocking the potential of native functionalities within your cross-platform applications. This allows you to build richer, more performant apps that leverage the best of both worlds. Remember to rebuild your app after making native code changes for them to take effect.


Defx, with its extensive experience in IT services, can help you navigate the complexities of React Native development and create robust, high-quality cross-platform applications.

See More

Contact Us

Let’s make your Idea into Reality

Let's Talk

logo
hello@defx.in