Zero to App Store in 30 Days

Integrating the web into our iOS app with React Native

Henry Arbolaez
Course Hero Engineering

--

This post is a high-level technical overview of how we integrated React Native (RN) into Course Hero’s flagship iOS app. Our first RN app, for our Textbook Solutions product, is now out in the wild.

The idea to implement RN came from a Course Hero internal hackathon project done by myself and Ernesto Rodriguez. We saw the opportunity to introduce Course Hero to this great technology, already in use at Shopify, Facebook, Instagram, Tesla, and more.

Though Course Hero currently uses React for web development, we also have separate mobile teams who maintain our mobile native apps. Using RN allowed web developers with good knowledge of React to apply their expertise towards building a mobile app. This flexibility allowed us to scale our textbook product to native platforms in order to give our customers a great experience.

Deep dive on the integration

RN Dependencies

When we started, we had a separate repository on GitLab: one for our web app, and another for our iOS app. We created a separate repository for the RN integration, which had the build file. There is no easy way of creating the two links, other than having them in a remote somewhere and fetching the build from a script inside the iOS repo or adding the RN inside the iOS repo. But we didn’t want the iOS team needing to clone any RN dependencies, and this was our first iteration anyway.

We started by adding the RN dependencies to the iOS Podfile. We then forked the RN project to our Course Hero Github Repo and then used the source method to clone the RN project to our local ~/.cocoapods/repos/coursehero dir. Now everyone who clones the iOS repo will automatically have the RN dependencies when doing pod install.

In Github, we made 0.63-stable our default branch. This helped us keep the RN project in sync with the Podfile. To change the default branch in GitHub: [repo] -> Settings -> Branches

Our Podfile will start to look something like this — react_native_pods been the method that encapsulates all the RN dependencies

Intro to RCTRootView

Doing the integration between the two sides is fairly simple. In iOS, we can use the subclass RCTRootView from the UIView class, which we can use in any location of our iOS app.

Most of all the Swift and the Obj-c code below is under the CourseHero iOS folder. CourseHero/ReactNative/Textbooks/

RNViewManager is going to a swift reusable class
Calling RNViewManager class

How do the two worlds communicate?

For the RN and native applications to communicate, we need a bridge — a way to send JSON data bidirectionally and asynchronously.

In our case, the RN app had a few modules that we needed to implement. From sending user information to sending callbacks and executing some business logic on the native side.

RN To Native

A key step in the process was creating a Native Module, which is a 3 step process.

The first step is to tell our native app about the RN bridge (we only need to perform this once), and then add the data below to the header.h file in our project. Note that there should only be one header file per project and it should conform to the standard naming convention, ProjectApp-Bridging-Header.h

Can be found in the Build Settings tab too

Next, we create our Modules. We started with TrackingModule.swift which allowed us to access the Native code from the RN side and report some tracking metrics to our internal tracking service.

Finally, we exposed the Swift class Module to RN by creating another file, typically the same name of the module above but with a .m extension representing Objective-C. This is typically referred to as an RN Macro.

Accessing the Swift module from React Native

With the native side set up, we moved to the RN project/App.js file, where we imported NativeModules from the react-native package. Any module exported from the Obj-C Macros will be available using the NativeModules object.

To recap, the process of creating a Native Module and exposing it to RN goes like this:

1. Create the Swift Module Class
2. Obj-C Macro which expose the Swift Module Class
3. NativeModules which is used in RN app, to access the module or methods exported from Objective-C
* @objc in the top of a swift method, is to export them to the Objective-C Class
* RCT_EXTERN_MODULE or RCT_EXPORT_MODULE (from objective-c code) - to export the module or methods to the RN

Native To React Native

When we instantiate RCTRootView , we can pass data into the initialProperties parameter. The data needs to be a NSDictionary, which then gets converted to a JSON object that we can access in the root component.

when we load the RN app, it adds a rootTag, which allows us to identifier the RCTRootView
Destrcuring props, which have currentUser

RCTRootView exposes another way of sending messages by using appProperties, which is helpful if you want to update the properties initialized in your RCTRootView and trigger a rerender of the root component.

We didn’t have a use case for using the RCTEventEmitter subclass, but this is the preferred way of emitting some events to signal that something has changed to the RN side.

Iteration Speed

RN allowed us to build, integrate and deploy the textbook app to the existing iOS app in less than a month. While doing the integration, we took advantage of hot reloading which allowed us to see the changes being made in RN almost instantly, compared to >20 seconds that native code would typically take to build.

Summary

By putting just a little effort to integrate React Native into our application stack, we quickly realized the advantages it would bring to our organization. There may be cases where React Native is not the right choice, but for us, it works great for our Textbook Solutions product and we look forward to building others using this technology. We hope this summary helps you get started on your React Native integration journey.

--

--

Henry Arbolaez
Course Hero Engineering

I'm a coffee lover, and a engineer at Course Hero. I'm passionate about the idea of bringing people together to collaborate and building a great products.