Let's dive deep into creating powerful native modules that bridge JavaScript and iOS seamlessly. ✨
🛠️ Step-by-Step: Create a Native Module in Swift
Let’s build a simple module called MyNativeModule
that:
- Sends data from JS to iOS 📤
- Sends events from iOS to JS 📩
1️⃣ Create MyNativeModule.swift (Swift) 💻
📄 File: MyNativeModule.swift
import Foundation import React @objc(MyNativeModule) class MyNativeModule: RCTEventEmitter { // MARK: - JS → iOS @objc func receivedData(_ params: NSDictionary, callback: RCTResponseSenderBlock) { print("📦 Received from JS:", params) // callback(["✅ iOS received your data!"]) } // MARK: - iOS → JS @objc func triggerMessageToRN() { let eventData: [String: Any] = ["message": "👋 Hello from iOS! 🎉"] sendEvent(withName: "onMessageFromNative", body: eventData) } // MARK: - Required Overrides override func supportedEvents() -> [String] { return ["onMessageFromNative"] } override static func requiresMainQueueSetup() -> Bool { return true } }
📝 This class extends RCTEventEmitter to support two-way communication.
2️⃣ Create Objective-C Bridge (MyNativeModule.m
) 🔌
Even though you’re using Swift, React Native still requires an Objective-C header to expose the module to JS.
📄 File: MyNativeModule.m
#import <Foundation/Foundation.h> #import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE(MyNativeModule, NSObject) RCT_EXTERN_METHOD(receivedData:(NSDictionary *)params callback:(RCTResponseSenderBlock)callback) RCT_EXTERN_METHOD(triggerMessageToRN:(NSDictionary *)params callback:(RCTResponseSenderBlock)callback) @end
🔗 This bridges Swift methods to the RN JS runtime.
🧠 Using the Native Module in JS (React Native Side)
Let’s test our newly created native module in a sample React Native app:
📄 File: App.js
import React, {useEffect} from 'react'; import { StyleSheet, View, Text, Button, NativeModules, NativeEventEmitter, } from 'react-native'; const {MyNativeModule} = NativeModules; const eventEmitter = new NativeEventEmitter(MyNativeModule); const App = () => { useEffect(() => { const subscription = eventEmitter.addListener( 'onMessageFromNative', data => { console.log('📨 Message from iOS:', data.message); } ); return () => subscription.remove(); }, []); const sendDataToiOS = () => { MyNativeModule.receivedData( { userName: 'amit@gmail.com', age: '29' }, response => console.log('✅ Callback from iOS:', response) ); }; return ( <View style={styles.container}> <Text style={styles.title}>🚀 React Native + Swift Bridge</Text> <Button title="📤 Send Data to iOS" onPress={sendDataToiOS} /> <Button title="📨 Receive Event from iOS" onPress={() => MyNativeModule.triggerMessageToRN()} /> </View> ); }; export default App; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, title: { fontSize: 20, marginBottom: 20, fontWeight: 'bold', }, });
✅ Results
🧪 Try it out:
- Tap Send Data to iOS → Check Xcode logs for received data.
- Tap Trigger iOS to JS → Watch for JS console logs like 📨 Message from iOS: Hello from iOS! 🎉.
⚙️ Troubleshooting Tips
✅ Clean your build folder (Cmd + Shift + K)
✅ Make sure RCT_EXTERN_MODULE is present
✅ Check that Swift is correctly initialized in your project
✅ Use use_frameworks! in your Podfile for Swift support
🏁 Final Thoughts
It easier and faster to bridge native code with JavaScript. With TurboModules, native communication is now more optimized and type-safe.
💡 Whether you’re building a native camera module, voice recognition, or secure authentication — the same pattern applies.
💬 Drop a Comment
Was this guide helpful? Stuck somewhere?
Drop a comment below👇
🔁 Don’t forget to like and share to help others in the RN community!
Top comments (0)