Integrating React Native into an existing Swift project

React Native is really nice. Its Cmd-R style development is refreshing compared to XCode’s build, deploy and run cycle. But if you want to use things like CoreData, NSOperationQueues or any of the other awesome libraries in the iOS world, you have to write bridges. In this blog post we will be focusing on adding React Native to an existing swift application. React Native’s secret is in its RCTRootView. So just like for the browser, React focuses on being a good view library and can be mixed with your existing swift application.

We’ll be using the XCode’s Single View Controller Swift project template for demonstration. React Native’s site has excellent documentation how you would go about such an integration. I add a few more things on top like loading from compiled / hosted JSBundle, caching the JSBundle and manually reloading React code after refreshing the cache. You can download the sample code from Github.

After you have your project and set it up with cocoapods, go ahead and initialize your package.json. My package.json looks like this. I have placed my package.json in the same location as my .xcodeproj and .xcworkspace.

Then go ahead and run npm install on the command line to install the necessary dependencies. This will create a node_modules folder. You can add this folder to your .gitignore file much like Pods directory for cocoapods.

You would then have to add React and its subspecs to your Podfile. My Podfile looks like this.

This adds references to the React Native pods and links them to your project as frameworks. Don’t forget to pod install after this. You can then add the entry point to the react native view. This file will be called index.ios.js by convention and we will be referring to it from our ViewController.

You can then start the react-native server by running npm start at the command line from the folder that has the file package.json. This should start a server that should be able to serve our react native bundle from localhost:8081.

I have used a simple View controller which has two views a RCTRootView that hosts the React Native app and a UIButton that will let me reload the code using the RCTBridge object of the RCTRootView. This is what my ViewController code looks like.

Running the app should present the app with React Native view loaded.

Bridging Swift views to React Native

Now this turned out to be trickier than I originally thought it would. React Native has a RCTViewManager class that expects you to return a View. Now the view can be configured with properties and you would have to export view using Obj-C macros. For the purposes of illustration, I am going to create a simple view that has a label and takes in property called message. It would then simply display the value of the message in a label concatenated with the word “Swifted”. Yeah… i made that nonsensical term up just now. I am going to create a view called CustomRNView.

Notice that I am exposing the swift class to the ObjC world using the @objc annotation. Now I have to write a RCTViewManager class that returns me this view.

This class CustomRNViewManager simply has a view method that returns a CustomRNView object. Also note that this class has also been annotated with the @objc annotation.

Now we have to expose it to the react world with the the RCT_EXTERN_MODULE and RCT_EXPORT_VIEW_PROPERTY macros. You will have to create the CustomRNView.h and CustomRNView.m files. The header declares our custom UIView as a RCTView and the implementation will export our CustomRNViewManager.

You do not have to put anything in the bridging header as we are loading rest of the React Native specs as frameworks.

Now, we have to get our CustomRNView to our javascript side. You can now use the requireNativeComponent method to refer to the exported module.

It should now display the CustomRNView within the react native view.

Caching the jsbundle

For the performance reasons, you might want to distribute the bundle with your app or better still load it the first time from a URL and then cache it to your documents directory. When you want to refresh then you can redownload the bundle and reload the code via RCTBridge. I have done precisely that in my ViewController.swift.

This will download the the file once and load it from the documents directory. You will also notice that the app launch time is significantly faster. You might want to consider using services like Microsoft CodePush to automatically download the latest code as you push changes to your code. We are very excited with this approach as we can be more agile with our existing swift apps by leveraging React Native and its code push strategies without having to go through the app compile, deploy and run cycles. Let us know your thoughts and opinions.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s