Building React Native 0.61.5 SDK to be used by native IOS applications (Swift)

Abdullah Asendar
6 min readNov 6, 2020

--

I was trying to build a react native SDK to be used by native IOS and Android applications. Android was “Kinda” easy to do, but i faced some issues with IOS and thought sharing what i did may help somebody.

In this article we will build a simple react native SDK, and integrate that SDK into a native IOS application. The goal is to make it easy for the SDK user, we don’t want to bother the SDK users with npm or react native related stuff.

Lest get things started…

Create React Native Project

Either create a new react native project or use an existing one,

react-native init MySdk --version 0.61.5

Add Some dependencies

Naturally, we would need some dependencies for our SDK, dependancies that require linking. For this article we will be using:

react-native-fast-image

yarn add react-native-fast-image

Finally install the pods

npx pod-install ios

Using FastImage

We are not going to do anything fancy on react native side, this is just a proof on concept. Just use the FastImage package that we added to make sure that it is working fine.

App.js

Create a native IOS wrapper for the React Native app

Running the created react native app is easy right? all you have to do is execute react-native run-ios. But running it inside another native app is a different story.

First, create a native IOS wrapper (wraps the react native app), that will contain all the required pods by react native. The wrapper will also configure and start the react app.

The idea is to create a native IOS framework, which will hide all react native complexity inside it. First, go to Xcode and create a new Framework project

In the next screen select a name for the framework and select Swift from the language dropdown. Let us name our framework MySdk-native.

After that open the terminal and cd into MySdk-native and execute:

pod init && pod install

We now have a CocoaPods framework, close Xcode and open generated MySdk-native.xcworkspace.

Next comes that hardest part, so buckle up!

Preparing the dependency pods

Now we have to prepare the pod dependancies for our SDK. These dependencies include all React Native dependencies in addition to any dependency that requires linking (such as react-native-fast-image).

React native

React native pods are local pods, because they are downloaded using npm or yarn. So one option is to embed these dependencies inside the SDK, or even better, upload these pods to a private podspec repo.

The problem is, if we take the podspecs the way they are, upload them to a private podspec repo, the pods will not be installed correctly. To better understand what this means, let us take a look at one of react native’s dependencies, FBLazyVector. Its located at node_modules/react-native/Libraries/FBLazyVector/FBLazyVector.podspec.

As you can see:
— The podspec requires package.json to get the version and license.
— The source is set to https://github.com/facebook/react-native.git
— source_files is set to “**/*.{c,h,m,mm,cpp}”

We have two problems here:
— This podspec will install every c,h,m,mm,cpp file in the react native repo
— It will require a package.json to be located at ../../package.json.

To solve these problems:
— Change the source_files to point to the correct directory, in this case:

s.source_files = “Libraries/FBLazyVector/**/*.{c,h,m,mm,cpp}”

— Make sure that the package path is set to:

package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))# we will place package json in that path in the next section

This way, when we add FBLazyVector as a dependency to our SDK, only Libraries/FBLazyVector contents will be installed.

React native uses a bunch of other pods, to find all pods used by react native, check the following file:

MySdk/ios/Podfile

The exact changes we made to FBLazyVector podspec above has to be done for all other react native pods!

I have already done this and uploaded the whole project to GitHub

Third party dependencies

For third party dependencies, it is much easier, we can use the pod dependencies as the following:

pod 'RNFastImage', :git => "git@github.com:DylanVann/react-native-fast-image.git", :tag=> 'v8.3.3'

Here, we are using RNFastImage pod by just pointing to its repository. However, the SDK user will have to add this to his/her pods as CocoaPods has no idea where RNFastImage is located. If you want the user to just have a single dependency, add any other third party dependency to your podspec repo.

Creating private Podspec repo

After setting up all react native podspecs, we can create a private podspec repo. The goal is to be able to import react native dependencies as:

pod 'React'

Looking at MySdk/ios/Podfile mentioned above, react native requires the following dependencies:

pod 'FBLazyVector'
pod 'FBReactNativeSpec'
pod 'RCTRequired'
pod 'RCTTypeSafety'
pod 'React'
pod 'React-Core'
pod 'React-CoreModules'
pod 'React-RCTActionSheet'
pod 'React-RCTAnimation'
pod 'React-RCTBlob'
pod 'React-RCTImage'
pod 'React-RCTLinking'
pod 'React-RCTNetwork'
pod 'React-RCTSettings'
pod 'React-RCTText'
pod 'React-RCTVibration'
pod 'React-cxxreact'
pod 'React-jsi'
pod 'React-jsiexecutor'
pod 'React-jsinspector'
pod 'Yoga'
pod 'DoubleConversion'
pod 'glog'
pod 'Folly'

The Podspec repo should be structured as the following:

.
+-- PodSpecRepo
| +-- package.json // this is react native's package.json
| +-- FBLazyVector // pod name
| | +-- 0.63.3 // pod version
| | | +-- FBLazyVector.podspec // the amended podspec
| +-- FBReactNativeSpec
| | +-- 0.63.3
| | | +-- FBReactNativeSpec.podspec
| +-- RCTRequired
| | +-- 0.63.3
| | | +-- RCTRequired.podspec
.... the rest of the dependencies

Upload you private repo to GitHub or Bitbucket. You can find the repo created in this article here.

Adding the pods to Podfile

Now we have all the pods needed for the react native app, add the following to MySdk-native Podfile:

Do not forget to add your podspec repo as a source on the top of of the Podfile

After that, cd to MySdk-native then execute:

pod install --repo-update

At this point, we can use react native classes inside our wrapper.

Run React Native inside the wrapper

Now we are all set, we want to start the react native app using the native wrapper that we created. This is explained and well documented in the official react native docs.

First, create a Swift class to be used as an interface for the SDK user, our class will simply contain one function that runs the react native app. That function will create a new RCTRootView and present it inside a controller.

Create a podspec for the SDK

It is important to create a podspec for the SDK so users can easily add it to their apps. Nothing special here, just an ordinary podspec.

The SDK in action

Moment of truth! let us test the SDK.

Create a simple swift app with a single button that will start our SDK. We will call this app MySdk-poc. Cd into the created app and execute:

pod init && pod install

Open the generated MySdk-poc.xcworkspace and add the following to the Podfile:

Then execute pod install again.

Create a button that will start react native on action:

Add the following to the info.plist of the poc:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>

This is needed only for debugging, to give the app the ability to connect to the metro bundler.

Start your react native project using yarn start then start the poc app!

Notes

— I used react native 0.61.5, other react native version may require different way of doing stuff.
— You may face some problems while building. For me, a lot of build problems were fixed by cleaning the build folder and building again.
— I am writing another article on how to setup production builds.

Project files

You can find all of the project files used in this article here:
https://github.com/AbdullahAsendar/react-native-ios-sdk

Thats all folks!
Abdullah Asendar

--

--