DEV Community

Cover image for Bridging in React Native with Pure C++ Modules New Architecture 0.79+: A Comprehensive Guide to Cross-Platform
Amit Kumar
Amit Kumar

Posted on

Bridging in React Native with Pure C++ Modules New Architecture 0.79+: A Comprehensive Guide to Cross-Platform

Introduction

React Native continues to evolve, and with version 0.79, bridging native code has become more efficient—especially when using Cross-Platform C++ Native Modules. Writing modules in C++ allows you to share platform-agnostic logic between Android and iOS with a single implementation, reducing duplication and improving performance.


In this guide, we'll walk through:

✅ Creating a C++ Turbo Native Module
✅ Configuring Codegen for scaffolding
✅ Implementing native logic once for both platforms
✅ Registering the module in Android & iOS
✅ Testing the module in JavaScript


💡 Why Use Cross-Platform C++?

Before diving into implementation, let’s understand why using C++ for native modules is a game changer:

✅ Single Source of Truth
With C++, you write the logic once and use it across both Android and iOS. No need to duplicate functionality in Kotlin and Swift/Objective-C—this greatly reduces development and maintenance effort.

🚀 Performance Optimized
C++ offers low-level system access and is highly optimized for performance. For CPU-intensive tasks such as encryption, string manipulation, and audio/video processing, C++ outperforms JavaScript and even many high-level native APIs.

🔄 Better Code Sharing
C++ modules can be reused not only between platforms but even across different apps or teams, especially if you’re building SDKs or libraries. This ensures consistency in logic across platforms.

🔒 Leverage Existing C++ Libraries
There’s a vast ecosystem of mature C++ libraries (e.g., OpenCV, SQLite, Boost). By writing C++ modules, you can tap into these without rewriting logic.

🧱 Tightly Integrated with React Native’s New Architecture
TurboModules and the JSI (JavaScript Interface) enable seamless and efficient communication between JS and C++. This means better memory management, faster calls, and lower overhead.


🚀 Step 1: Create the JavaScript Specs

Turbo Native Modules require a specification file (written in TypeScript) that defines the module's interface.

  1. Create a specs folder in your project root.
  2. Add NativeSampleModule.ts with the following:
import { TurboModule, TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  reverseString(input: string): string;
}

export default TurboModuleRegistry.getEnforcing<Spec>('NativeSampleModule');
Enter fullscreen mode Exit fullscreen mode

🔹 Key Notes:

  • The file must start with Native (e.g., NativeSampleModule.ts).
  • The Spec interface defines the module's methods.

🚨 Important Note About Spec Files

When creating your spec file (NativeSampleModule.ts), you must:

  • Keep it as a TypeScript (.ts) file - Don't change it to JavaScript (.js) or Codegen won't process it
  • Always prefix with "Native" - The filename must start with Native (e.g., NativeSampleModule.ts), otherwise Codegen will ignore it

⚙️ Step 2: Configure Codegen

Update package.json with the following configuration, making sure to replace com.yourpackagename with your actual package name:

"codegenConfig": {
  "name": "AppSpecs",
  "type": "modules",
  "jsSrcsDir": "specs",
  "android": {
    "javaPackageName": "com.yourpackagename.specs"  // ← Replace with your package name!
  }
}
Enter fullscreen mode Exit fullscreen mode

This tells Codegen where to find the specs and how to generate scaffolding


💻 Step 3: Write the C++ Native Module

Create a shared Folder

Place it at the same level as android and ios.

Define the Header (NativeSampleModule.h)

//shared/NativeSampleModule.h

#pragma once
#include <AppSpecsJSI.h>
#include <memory>
#include <string>

namespace facebook::react {
class NativeSampleModule : public NativeSampleModuleCxxSpec<NativeSampleModule> {
 public:
  NativeSampleModule(std::shared_ptr<CallInvoker> jsInvoker);
  std::string reverseString(jsi::Runtime& rt, std::string input);
};
} // namespace facebook::react
Enter fullscreen mode Exit fullscreen mode

Implement the Module (NativeSampleModule.cpp)


//shared/NativeSampleModule.cpp

#include "NativeSampleModule.h"

namespace facebook::react {
NativeSampleModule::NativeSampleModule(std::shared_ptr<CallInvoker> jsInvoker)
    : NativeSampleModuleCxxSpec(std::move(jsInvoker)) {}

std::string NativeSampleModule::reverseString(jsi::Runtime& rt, std::string input) {
  return std::string(input.rbegin(), input.rend());
}
} // namespace facebook::react
Enter fullscreen mode Exit fullscreen mode

🔹 What’s Happening?

  • The header declares the module structure.
  • The implementation reverses a string (shared logic for both platforms).

Image description


🤖 Step 4: Register the Module in Android

1. Add CMakeLists.txt

Create android/app/src/main/jni/CMakeLists.txt:

cmake_minimum_required(VERSION 3.13)

# Define the library name here.
project(appmodules)

# This file includes all the necessary to let you build your React Native application
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

# Define where the additional source code lives. We need to crawl back the jni, main, src, app, android folders
target_sources(${CMAKE_PROJECT_NAME} PRIVATE ../../../../../shared/NativeSampleModule.cpp)

# Define where CMake can find the additional header files. We need to crawl back the jni, main, src, app, android folders
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ../../../../../shared)
Enter fullscreen mode Exit fullscreen mode

2. Update build.gradle

    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

+   externalNativeBuild {
+       cmake {
+           path "src/main/jni/CMakeLists.txt"
+       }
+   }
}
Enter fullscreen mode Exit fullscreen mode

3. Register the new Turbo Native Module

The final step is to register the new C++ Turbo Native Module in the runtime, so that when JS requires the C++ Turbo Native Module, the app knows where to find it and can return it.

  1. From the folder SampleApp/android/app/src/main/jni, run the following command:
curl -O https://raw.githubusercontent.com/facebook/react-native/v0.76.0/packages/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp
Enter fullscreen mode Exit fullscreen mode
  1. Then, modify this file as follows:
android/app/src/main/jni/OnLoad.cpp

#include <DefaultComponentsRegistry.h>
#include <DefaultTurboModuleManagerDelegate.h>
#include <autolinking.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <rncore.h>

+ // Include the NativeSampleModule header
+ #include <NativeSampleModule.h>

//...

std::shared_ptr<TurboModule> cxxModuleProvider(
    const std::string& name,
    const std::shared_ptr<CallInvoker>& jsInvoker) {
  // Here you can provide your CXX Turbo Modules coming from
  // either your application or from external libraries. The approach to follow
  // is similar to the following (for a module called `NativeCxxModuleExample`):
  //
  // if (name == NativeCxxModuleExample::kModuleName) {
  //   return std::make_shared<NativeCxxModuleExample>(jsInvoker);
  // }

+  // This code register the module so that when the JS side asks for it, the app can return it
+  if (name == NativeSampleModule::kModuleName) {
+    return std::make_shared<NativeSampleModule>(jsInvoker);
+  }

  // And we fallback to the CXX module providers autolinked
  return autolinking_cxxModuleProvider(name, jsInvoker);
}

// leave the rest of the file
Enter fullscreen mode Exit fullscreen mode

🍏 Step 5: Register the Module in iOS

To make sure that the iOS app can effectively build the C++ Turbo Native Module, we need to:

  1. Install pods and run Codegen.
  2. Add the shared folder to our iOS project.
  3. Register the C++ Turbo Native Module in the application.

1. Install Pods and Run Codegen.

cd ios
bundle install
bundle exec pod install
Enter fullscreen mode Exit fullscreen mode

2. Add the shared folder to the iOS project

This step adds the shared folder to the project to make it visible to Xcode.

1. Open the CocoPods generated Xcode Workspace.
cd ios
open SampleApp.xcworkspace
Enter fullscreen mode Exit fullscreen mode

2. Click on the SampleApp project on the left and select Add files to "Sample App"....

Image description


3. Select the shared folder and click on Add.

Image description


If you did everything right, your project on the left should look like this:

Image description


3. Registering the Cxx Turbo Native Module in your app

To register a pure Cxx Turbo Native Module in your app, you need to:

  1. Create a ModuleProvider for the Native Module
  2. Configure the package.json to associate the JS module name with the ModuleProvider class.

The ModuleProvider is an Objective-C++ that glues together the Pure C++ module with the rest of your iOS App.

3.1 Create the ModuleProvider

  1. From Xcode, select the SampleApp project and press ⌘ + N to create a new file.
  2. Select the Cocoa Touch Class template
  3. Add the name SampleNativeModuleProvider (keep the other field as Subclass of: NSObject and Language: Objective-C)
  4. Click Next to generate the files.
  5. Rename the SampleNativeModuleProvider.m to SampleNativeModuleProvider.mm. The mm extension denotes an Objective-C++ file.
  6. Implement the content of the SampleNativeModuleProvider.h with the following:
NativeSampleModuleProvider.h

#import <Foundation/Foundation.h>
#import <ReactCommon/RCTTurboModule.h>

NS_ASSUME_NONNULL_BEGIN

@interface NativeSampleModuleProvider : NSObject <RCTModuleProvider>

@end

NS_ASSUME_NONNULL_END
Enter fullscreen mode Exit fullscreen mode

This declares a NativeSampleModuleProvider object that conforms to the RCTModuleProvider protocol.


  1. Implement the content of the SampleNativeModuleProvider.mm with the following:
NativeSampleModuleProvider.mm


#import "NativeSampleModuleProvider.h"
#import <ReactCommon/CallInvoker.h>
#import <ReactCommon/TurboModule.h>
#import "NativeSampleModule.h"

@implementation NativeSampleModuleProvider

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
  return std::make_shared<facebook::react::NativeSampleModule>(params.jsInvoker);
}

@end
Enter fullscreen mode Exit fullscreen mode

3.2 Update the package.json

Modify the package.json as it follows:

     "start": "react-native start",
     "test": "jest"
   },
   "codegenConfig": {
     "name": "AppSpecs",
     "type": "modules",
     "jsSrcsDir": "specs",
     "android": {
       "xxxx": "com.xxp.xx"
     },
     "ios": {
        "modulesProvider": {
          "NativeSampleModule":  "NativeSampleModuleProvider"
        }
     }
   },

   "dependencies": {
Enter fullscreen mode Exit fullscreen mode

At this point, you need to re-install the pods to make sure that codegen runs again to generate the new files:


🧪 Step 6: Test in JavaScript

Modify App.tsx:

import React from 'react';
import { Button, SafeAreaView, Text, TextInput, View } from 'react-native';
import SampleTurboModule from './specs/NativeSampleModule';

function App() {
  const [value, setValue] = React.useState('');
  const [reversedValue, setReversedValue] = React.useState('');

  const onPress = () => {
    const revString = SampleTurboModule.reverseString(value);
    setReversedValue(revString);
  };

  return (
    <SafeAreaView>
      <Text>Enter text to reverse:</Text>
      <TextInput value={value} onChangeText={setValue} />
      <Button title="Reverse" onPress={onPress} />
      <Text>Reversed: {reversedValue}</Text>
    </SafeAreaView>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

🎉 Conclusion

You’ve successfully created a cross-platform C++ Turbo Native Module in React Native 0.79!

🔹 Benefits:

  • ✔ Single codebase for Android & iOS
  • ✔ Better performance with C++
  • ✔ Type-safe with Codegen

Try extending this by adding more methods or integrating third-party C++ libraries!

🚀 Happy Coding! 🚀


Further Reading

C++ for Mobile Development


Would you like a deep dive into advanced C++ module optimizations? Let me know in the comments! 👇

Top comments (0)