iOS Native Module on React Native

Pasindu Yeshan Abeysinghe
7 min readMar 22, 2022

--

If you are not familiar with React Native, React Native is a JavaScript framework for writing mobile applications which eventually rendered natively. React Native runs on React, a popular open-source library for building user interfaces with JavaScript, So if you know React it will be really easy to develop user interfaces in React Native mobile applications. That is one reason React native is so popular.

Native Module

The NativeModule system exposes instances of native classes to JavaScript as JavaScript objects. When you run npx react-native run-android it runs your react native mobile application on Android OS and all the native modules you have written in the Android folder will be accessible in react native. You can read my previous article to learn how to write Android Native Module using Kotlin. In this article, I will talk about how you can do that in iOS using … mmm. Let’s see what we’re gonna use.

Swift or Objective-C

You can develop an iOS native module using both Swift and Objective-C. If we compare Swift and Objective-C even though both of them are native languages for iOS, Swift is a much more modern language and it’s more human-friendly and easy to learn. Moreover, applications written in Swift are said to have only 30% of lines of code compared to one written in Objective-C. According to Apple Swift is 2.6 times faster than Objective-C 😎. But, the layout engine (Yoga) used in React Native stays in Objective-C, therefore, using Objective-C in native development is very straightforward but that doesn’t mean you can not use Swift. If you are familiar with Swift or kind of don’t like the syntax of Objective-C 😢 you can still write the native module with Swift easily and you will need an additional bridging file, known as a bridging header, to expose the Objective-C files to Swift. I will be focusing on writing the native module in Swift here.

Getting Started

First of all, we should have a React Native project 😃 So, if you don’t have a react native project click here and follow the instructions given under the React Native CLI Quickstart. The reason I’m telling you to use React Native CLI instead of Expo CLI which is way easier to use than React Native CLI is, integrating native modules in Expo is a nightmare. You can read more about this matter from here.

Okay, now we can jump into iOS native module development, for that, I recommend using Xcode for writing native modules since it will help you resolve simple errors like syntax errors easily.

First, open the ios folder from Xcode and create a New Group option, this won’t create a new folder though, if you want your native module in a separate folder select the option “New group with Folder”.

Native Module Header File

The next step is to create a header file containing the interface of your native module. Create your header file inside the group you have created earlier.

When you open EntgraServiceModule.h file you will see autogenerated code like below. Don’t worry I will explain it. 😃

When the code is compiled, the preprocessor checks whether EntgraSeerviceModule_h has been previously defined. If not, the compiler defines EntgraSeerviceModule_h and includes the contents of the file. If the header is included again into the same file, EntgraSeerviceModule_h will already have been defined from the first time that the contents of the header were included; the ifndef guard will then ensure that the contents of the header will be ignored.

Okay, now you what this auto-generated code means, now let’s define our Native Module interface here. First, you need to import React/RCTBridgeModule.j. The class definition starts with the keyword @interface followed by the class name and type. A class should implement RCTBridgeModule to register as a native module in Objective-C

If you get an error like React/ReactBridgeModule.h file not found don’t worry I got you covered 😃. Follow these steps.

rm -r node_modules/
rm -r ios/Pods
npm install
cd ios && pod install
Open XCode, hit CMD + Shift + K to clean and build

Now we are done with the header file. Easy right 😆.

Native Module Implementation

Now let’s implement our native module. For that, you should create an Objective-C file as below.

Then import your header file into the Objective-C file.

#import “EntgraServiceModule.h”

You can start implementing your native module after the keyword @implementation and native module name. RCT_EXPORT_MODULE() export and register native module class with React Native. You can pass any name to this method as a parameter and your native module class will be registered to React Native by that name.

#import <Foundation/Foundation.h>
#import “EntgraServiceModule.h”
@implementation EntgraServiceModule// Export EntgraServiceModule
RCT_EXPORT_MODULE(EntgraServiceManager);
@end

This argument is not a string literal. So don’t pass name as RCT_EXPORT_MODULE("EntgraServiceManager").

If you read my previous article you may have noticed, I named my Android native module as EntgraServiceManager. So that’s why I use the same name in iOS as well. In fact, you need to use the same name and same method formats inside these native modules. Otherwise, you will have to check the OS and then invoke each method according to the OS which is additional work.

Export Native Method to React Native

Now we have registered our native module to React Native. Unfortunately, like in Android, in iOS React Native will not expose any methods in a native module to JavaScript unless explicitly told to. But it’s not that hard, you can use RCT_EXPORT_METHOD() to export your native method to React Native.

Methods written in the RCT_EXPORT_METHOD macro are asynchronous and the return type is therefore always void. Therefore, we can’t just return values. You can use callback functions to overcome this issue and return any value from the native module to React native. Here I pass two callback functions as parameters for each method which will be invoked in success and error.

For iOS, callbacks are implemented using the type RCTResponseSenderBlock and it only accepts one argument which is an array of parameters to pass to the JavaScript callback.

One more thing before we test our native module. It’s always good to declare your native methods in the header file inside the interface. (OOP concepts 😜) As a result, you will get a warning when you haven’t implemented any defined function in your implementation.

Woo-hoo we are done with the native module. 😎 Now let’s see how this can be accessed in React Native.

Testing Native Module

You can build a wrapper for the native module instead of using it directly each time you access your native module. If you are using typescript you can make your code type-safe by adding type annotation to your native module as follows. It will make your code cleaner and easier to use.

Then you can use this native module anywhere as follows.

Ok, you are all set to go. First, you will need to start the Metro, the Javascript bundler by running npx react-native start inside your project folder. Then open another terminal and run npx react-native run-ios to start your application. Make sure to run npx react-native run-ios each time you update your native module.

Thank you for reading and hope you got some insight on developing iOS native modules for React Native 😃

--

--

Responses (1)