I was tinkering with react native recently and learned a few things about setting up the dev environment and running it. This post details my experience. As a next step, I wanted to explore how we can integrate a react native code module into an existing iOS app.
Here is the official documentation on how to do it. While it looks just fine, there are a few aspects about it that can be improvised. Not all the steps are needed and the sample app they refer to in the documentation is no longer available on Github. This post is my attempt to fix the shortcomings of the original.
All the steps below are tested and validated on a MacBook Pro M1 MAX running MacOS Monterey 12.5 with Xcode 13.4.1, Android studio Chipmunk, and Visual Studio Code 1.70.0.
Please make sure you have your dev environment set up correctly and you are able to run a react native app in an Android emulator or device. This is very important to continue with the next steps. You may refer to this post in case you need a little bit of help doing it.
The concept on a high level is to set up the react native dependencies in an accessible folder and then configure the Cocoapods to use those dependencies. Once that is done, use ‘RCTRootView’ to render the react native UI inside the native app.
Here are the main steps that need to be performed.
- Create a directory structure and set up the dependencies.
- Create a react native component
- Create an iOS project
- Set up dependencies using the pod file
- Add code changes in the native iOS app
Now the steps in detail:
1. Create a directory structure and set up the dependencies.
Create a root folder where the react native module and the existing (or new) iOS app coexist.
mkdir integratedReactNativeProject
Create a package.json file that will have the basic project information and other dependency details.
cd integratedReactNativeProject && touch package.json
Open the package.json which is just created in any text editors and add these lines:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
If you don’t have it already, install yarn
npm i yarn
Install the react
and react-native
packages using yarn.
yarn add react-native
You can see the log messages being added to the terminal. Search for the word ‘peer’ and note down the dependencies mentioned there. Here is an example:
Based on the above message we need to install babel/core, react18.0.0, babel/preset-env.
Either add each one of them one by one or install it once.
yarn add react@18.0.0
yarn add @babel/core
yarn add react-native
or
yarn add @babel/preset-env && yarn add @babel/core && yarn add react@18.0.0
Once done, you can see that all these dependencies are added in package.json, and also a node_modules folder is added to the root directory.
2. Create a react native component
In this step, we will create a barebone react-native ‘hello’ world screen.
Create an index.js file inside the root folder, add the below lines and save it.
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';const HelloWorld = () => {
return (
<View style={styles.container}>
<Text style={styles.hello}>Hello, World</Text>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10
}
});AppRegistry.registerComponent(
'MyReactNativeApp',
() => HelloWorld
);
3. Create an iOS project
Assuming that you are still inside the root directory, we will create a subfolder called ‘ios’ and within this newly created subfolder add an ios project.
mkdir ios
Please note that you can either create a brand-new ios app and save it inside this subfolder or just copy and paste an existing ios app project files here.
I am taking the first option which is creating a new app. Using Xcode, create a new project.
Run the app and make sure it runs on Simulator. I chose the ‘iPhone 13’ simulator. You should see a blank white screen on the simulator.
4. Set up dependencies using the pod file
If you have not already, now is the time to install cocoapods.
brew install cocoapods
Once it is done, go to the ‘ios’ folder and init the pods
pod init
This will generate a pod file. Open the pod file in any text editor and add these lines at the top:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
Add the below line under ‘target’ block:
use_react_native!
The pod file should look like this now:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'target 'MyApp' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
use_react_native!# Pods for MyAppend
After you have created your Podfile, you are ready to install the React Native pod.
$ pod install
You should see the dependencies being installed as below:
Once over, you will see many files added to the project including a pod project and a new workspace. In this case, ‘MyApp.xcworkspace’.
5. Add code changes in the native iOS app
Open the ‘MyApp.xcworkspace’ and check if it compiles successfully.
Open the ViewController.swift, and add an import statement for react
import React
Override the loadView() method so that it calls a function that reassigns the ‘view’ to an instance of ‘RCTRootView’.
The code will look like the below:
import UIKitimport Reactclass ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view.}override func loadView() {loadReactNativeView()}func loadReactNativeView() {let jsCodeLocation = URL(string: "http://localhost:8081/index.bundle?platform=ios")!let rootView = (bundleURL: jsCodeLocation,moduleName: "MyReactNativeApp",initialProperties: nil,launchOptions: nil)self.view = rootView}}
We are almost there. Assuming that you are still in the root folder, which is ‘integratedReactNativeProject’ in this case, run the below command:
yarn start
This will start the metro server. You should see something like this:
Please note that the module name, ‘MyReactNativeApp’ here has to be the same as the one provided for AppRegistry.registerComponent() function of index.js file.
Now, run the app in Xcode.
If everything is working as expected you should see the ‘hello world’ message on the simulator screen.
Hope this worked for you.
What is shown above is the simplest example. Please refer to the original documentation to know more about how to communicate between react world and the native world. Thanks for your time.
References:
My other posts about react-native:
Setting up ReactNative on Mac OSX + Apple Silicon
How to integrate react native code with an existing Android app?