---
title: "Simplify Your iOS Brownfield Integration With RootViewFactory"
description: "Learn how RootViewFactory streamlines brownfield integration and helps migrate existing iOS apps to React Native efficiently."
url: https://www.callstack.com/blog/simplify-your-ios-brownfield-integration-with-rootviewfactory
updated: 2026-10-24T08:39:37.147Z
---

# Simplify Your iOS Brownfield Integration With RootViewFactory

Learn how RootViewFactory streamlines brownfield integration and helps migrate existing iOS apps to React Native efficiently.

_By Oskar Kwaśniewski, Software Developer @ Callstack · Published 2024-10-01 · Category: Brownfield_

Many teams that have made native apps are starting to add React Native to their existing codebase. There are many reasons behind it - the most important being probably the ability to develop features with one code for multiple platforms.

However, to make the most of it, developers should aim at the latest React Native version possible to leverage the New Architecture. In terms of brownfield development, it might be a little bit tricky, though. Let’s see how to enable it in brownfield apps and what we can do to make it easier.

## Enabling the New Architecture in a brownfield app

In general, when [integrating React Native in an iOS native app](https://www.callstack.com/blog/ios-brownfield-app-with-react-native-in-an-easy-way), to turn it into a brownfield app you should use RCTRootView. It’s a UIView that holds a React Native root, providing the interface between the hosted app and the native side at the same time. Let’s say we have an RCTRootView in our brownfield app, and we initialize like this:

[GitHub Gist](https://gist.github.com/okwasniewski/42ba174003c28a1aa3ec8edc24f2c513)

This RCTRootView initializer is intended to be used with the app as a single RCTRootView, and the bridge is created internally.

However, if you want to switch to the New Architecture in a brownfield app and use Fabric as a renderer, it takes a few more steps as you need to refactor the code on the app side. With Fabric enabled, you should move from RCTRootView to RCTFabricSurfaceHostingProxyRootView, or eventually use a proper renderer based on the RCT\_NEW\_ARCH\_ENABLED flag. The setup is quite verbose; if you are interested in the details, you can [take a look at the implementation](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm) of RCTRootViewFactory.

Thankfully, we don’t need to do any of this! Let’s go over the implementation.

## Changes in AppDelegate

First step is subclassing your AppDelegate to RCTAppDelegate, which internally creates RCTRootViewFactory and sets up all the necessary parts to make React Native work.

> Note: If you don't want to subclass RCTAppDelegate an alternative approach is being developed called ReactNativeFactory, which decouples RCTAppDelegate from the initialization flow.

[GitHub Gist](https://gist.github.com/okwasniewski/bafb5d123fab4ca7d083553b27b11700)

This sets up our AppDelegate to play nicely with React Native. Notice how we call self.automaticallyLoadReactNativeWindow = false this prevents RCTAppDelegate's applicationDidFinishLaunchingWithOptions method from initializing the default React Native window and a view controller.

On top of that we also need to inform React Native about the source of our JavaScript bundle. In order to do so, add those two methods do your AppDelegate:

[GitHub Gist](https://gist.github.com/okwasniewski/33712908f938f066f43da109292d3729)

Next step: Use RCTRootViewFactory to spawn new views when needed.

### Example usage

As an example, let’s use a brownfield app written in SwiftUI ([GitHub repository](https://github.com/okwasniewski/react-native-brownfield-swiftui)) and leverage React Native for one of the tabs using native TabView component.

First let's use the AppDelegate above in our SwiftUI App struct:

[GitHub Gist](https://gist.github.com/okwasniewski/160ce5fc22eaa400b73f57db8c1e52ff)

In order to bridge React Native to SwiftUI let's use UIViewRepresentable to create a new React Native root view inside.

Below we create a new struct called ReactNativeView which accepts moduleName and rootViewFactory to create a new view.

[GitHub Gist](https://gist.github.com/okwasniewski/16c5b09eae29947394098f1d4bbebc7e)

Module name is the parameter passed to AppRegistry.registerComponent function call on the JavaScript side.

Example:

[GitHub Gist](https://gist.github.com/okwasniewski/f5c8a440652ffd7df163574d040535ac)

Also if you want to pass some additional props to React Native view, you can invoke viewWithModuleName:initialProperties method and pass a dictionary:

[GitHub Gist](https://gist.github.com/okwasniewski/7477640c1d6427d9982072d0d50eb823)

On the JavaScript side you can use those props like this:

[GitHub Gist](https://gist.github.com/okwasniewski/74c27be0497cf1cebb7dad267518dd7d)

Now let's drop in the ReactNativeView struct passing module name and rootViewFactory that we can retrieve from AppDelegate:

[GitHub Gist](https://gist.github.com/okwasniewski/d06b2667a05ea20258c972af9b5f3d4b)

### Results

As a result we get clean integration of React Native into a native SwiftUI app, allowing us to gradually migrate to React Native for screens we need.

React Native window is loaded after the user visits this tab, keeping in mind resource management.

![GIF showing integration of React Native into a native SwiftUI app](https://www.callstack.com/assets/CleanShot2024-09-26at14.39.35-ezgif.com-resize.gif)

## Conclusions

RootViewFactory API is a valuable tool that simplifies the process of integrating React Native with your existing iOS or macOS app. By adopting this pattern you can make your migration to the New Architecture easier and streamline the upgrading experience of React Native in your brownfield apps.
