Skip to main content

Integrating React Native into Existing Apps

Learn how to integrate React Native into your existing native iOS or Android application. This allows you to gradually adopt React Native without rewriting your entire app.

Overview

React Native can be embedded into existing native applications, allowing you to:
  • Develop new features in React Native while keeping existing native code
  • Gradually migrate native screens to React Native
  • Share code between iOS and Android for new features
  • Leverage native modules and React Native simultaneously

Integration Approach

There are two main approaches:
  1. Full App Integration: Add React Native to your entire app build process
  2. Screen-by-Screen: Integrate React Native for specific screens or features

Android Integration

Prerequisites

  • Existing Android application (Android 6.0+, API level 24+)
  • Node.js installed
  • React Native package

Setup Steps

1

Add React Native to package.json

Create a package.json in your project root:
{
  "name": "ExistingApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "react-native start"
  },
  "dependencies": {
    "react": "^18.3.1",
    "react-native": "^1000.0.0"
  }
}
Install dependencies:
npm install
2

Configure build.gradle

Update your app’s build.gradle:
android {
    compileSdkVersion 35
    
    defaultConfig {
        applicationId "com.your.app"
        minSdkVersion 24
        targetSdkVersion 35
    }
    
    configurations.all {
        resolutionStrategy {
            force "com.facebook.react:react-android:1000.0.0"
        }
    }
}

dependencies {
    implementation "com.facebook.react:react-android:+"
    implementation "com.facebook.react:hermes-android:+"
}
3

Implement ReactApplication

Modify your Application class:
package com.your.app

import android.app.Application
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader

class MainApplication : Application(), ReactApplication {

    private val reactNativeHost = object : DefaultReactNativeHost(this) {
        override fun getUseDeveloperSupport() = BuildConfig.DEBUG

        override fun getPackages(): List<ReactPackage> {
            return listOf(
                // Add your native modules here
            )
        }

        override fun getJSMainModuleName() = "index"
    }

    override fun getReactNativeHost(): ReactNativeHost = reactNativeHost

    override fun onCreate() {
        super.onCreate()
        SoLoader.init(this, false)
    }
}
4

Create React Native Activity

package com.your.app

import android.os.Bundle
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultReactActivityDelegate

class MyReactActivity : ReactActivity() {

    override fun getMainComponentName(): String = "MyReactNativeApp"

    override fun createReactActivityDelegate(): ReactActivityDelegate {
        return DefaultReactActivityDelegate(
            this,
            mainComponentName,
            false
        )
    }
}
5

Launch from native code

From any Activity:
val intent = Intent(this, MyReactActivity::class.java)
startActivity(intent)

iOS Integration

Prerequisites

  • Existing iOS application (iOS 13.4+)
  • CocoaPods installed
  • Node.js installed

Setup Steps

1

Install React Native dependencies

Create package.json and install:
{
  "name": "ExistingApp",
  "version": "0.0.1",
  "dependencies": {
    "react": "^18.3.1",
    "react-native": "^1000.0.0"
  }
}
npm install
2

Configure Podfile

Create or update ios/Podfile:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, min_ios_version_supported

target 'YourApp' do
  config = use_native_modules!
  
  use_react_native!(
    :path => config[:reactNativePath],
    :hermes_enabled => true
  )
  
  post_install do |installer|
    react_native_post_install(installer, config[:reactNativePath])
  end
end
Install pods:
cd ios && pod install
3

Create RCTRootView in ViewController

#import "ViewController.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

@implementation ViewController

- (void)loadReactNativeView {
    NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] 
        jsBundleURLForBundleRoot:@"index"];
    
    RCTRootView *rootView = [[RCTRootView alloc] 
        initWithBundleURL:jsCodeLocation
        moduleName:@"MyReactNativeApp"
        initialProperties:@{}
        launchOptions:nil];
    
    rootView.frame = self.view.bounds;
    [self.view addSubview:rootView];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self loadReactNativeView];
}

@end
4

Configure App Transport Security

Update Info.plist for Metro bundler access:
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

React Native Code

Create index.js in your project root:
import { AppRegistry } from 'react-native';
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const MyReactNativeApp = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>
        Welcome to React Native!
      </Text>
    </View>
  );
};

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

AppRegistry.registerComponent(
  'MyReactNativeApp',
  () => MyReactNativeApp
);

Running the Integrated App

1

Start Metro bundler

npx react-native start
2

Build and run native app

Android:
./gradlew installDebug
iOS: Open Xcode and click Run, or:
xcodebuild -workspace ios/YourApp.xcworkspace -scheme YourApp

Communication Between Native and React Native

Passing Data to React Native

Android:
val bundle = Bundle()
bundle.putString("message", "Hello from native")

val intent = Intent(this, MyReactActivity::class.java)
intent.putExtras(bundle)
startActivity(intent)
iOS:
NSDictionary *initialProps = @{
    @"message": @"Hello from native"
};

RCTRootView *rootView = [[RCTRootView alloc]
    initWithBundleURL:jsCodeLocation
    moduleName:@"MyReactNativeApp"
    initialProperties:initialProps
    launchOptions:nil];

Native Modules

Create custom native modules to expose native functionality to React Native:
// Android
class MyNativeModule(reactContext: ReactApplicationContext) 
    : ReactContextBaseJavaModule(reactContext) {
    
    override fun getName() = "MyNativeModule"
    
    @ReactMethod
    fun showToast(message: String) {
        Toast.makeText(reactContext, message, Toast.LENGTH_SHORT).show()
    }
}

Best Practices

  1. Start Small: Begin by integrating one screen or feature
  2. Use Native Modules: Leverage existing native code through native modules
  3. Handle Lifecycle: Properly manage React Native lifecycle in your native app
  4. Test Thoroughly: Test integration points between native and React Native
  5. Performance: Monitor performance impact of the integration

Troubleshooting

Metro Bundler Connection Issues

Ensure your device/emulator can reach Metro:
  • Android: adb reverse tcp:8081 tcp:8081
  • iOS: Check firewall settings

Native Module Not Found

Rebuild native app after adding dependencies:
# Android
cd android && ./gradlew clean

# iOS
cd ios && pod install

Next Steps

Build docs developers (and LLMs) love