React Native has revolutionised how mobile applications are developed, offering a seamless bridge between JavaScript and native code for building cross-platform apps. While React Native provides an extensive set of APIs for accessing device features and functionalities, there are times when developers need to tap into the power of native languages like Java, Kotlin, Objective-C, or Swift to accomplish tasks that go beyond the capabilities of JavaScript.

That's where Native Modules come in.

In this blog post, Scott walks you through how to integrate Native iOS code into a React Native project for iOS.

Looking to integrate Native Modules into your Expo application? Book a free 30-minute consultation with one of our Expo specialists today.

Read: "React Native Year in Review 2023 - Key Updates & Highlights"

React Native and Native Modules

In React Native app development, Native Modules refer to modules written in native programming languages - Java or Kotlin for Android and Swift or Objective-C for iOS. 

React Native enables developers to write most of their code in JavaScript, but sometimes, it's necessary to interact with native code to access device-specific features. In these cases, React Native provides a bridge between JavaScript and native modules, called Native Module System. Native modules enable communication between JavaScript code and native code and are particularly useful for tasks that require access to device features that are not exposed through standard React Native APIs.

Common use cases for native modules in React Native include accessing device-specific features like the camera or sensors, integrating with third-party native libraries, or optimising performance.

Developers use the 'NativeModules' API provided by React Native to access native modules from JavaScript. This API allows JavaScript code to call methods defined in the native modules.

Native Module example:

How to Integrate Native Modules for iOS

If you have Swift files only, you'll need to do a few things:

  • Create the bridging header file (.h extension)
  • Create the bridging files (.m extension)
  • Mark swift files with @objc decorator
  • Add relevant changes to your podfile (if needed)
  • Add relevant changes to appdelegate (if needed)
  • Include the files in your pbxproj

Create the bridging header file (.h)

This is a simple step - you create a file with only the following contents:

***IMPORTANT: This file MUST be named in a specific way. Let's assume the library you're adding is called ReactNativeJellyNetworkSdk (this is a random name, completely unrelated to anything), then your bridging header file should be called ReactNativeJellyNetworkSdk-Bridging-Header.h.

This file will go at the very root of your iOS project (i.e. in the ./ios folder).

Create the bridging files (.m)

This part may be very easy or very difficult depending on your native knowledge. This file is essentially a way for Xcode to bridge between the Swift code you've got and expose a native method (since we can't use Swift files on their own). For each Swift file, you would want 1 bridging file with the same name but different extension. For example, AuthModule.swift should have a corresponding AuthModule.m file.Xcode may be able to create these for your automatically if you import them that way (recommended), but if not, it's possible to create them manually. Let's look at an example.Say that your AuthModule.swift has a function defined like this:

Your AuthModule.m would look like this:

You'd need to add RCT_EXTERN_METHOD() declarations for each function exposed by your swift module.

You'll need to add these files to your project - you can add them wherever you want, but make a note of the locations if you're not working directly inside Xcode (as you'll need to manually update the pbxproj definitions).

Mark swift files with @objc decorator

For each function in your swift file, mark it with @objc. For example, using our register function above as an example, the new version looks like this:

Additionally, your Swift module class itself needs the decorator too. For example:

Add relevant changes to your podfile + appdelegate

This could be easy or difficult, again depending on your knowledge. If your library requires you to make any changes to your podfile or appdelegate, you'll need to also include these.

Include the files in your pbxproj (Xcode and Expo)

If you're working inside Xcode, then importing the files will automatically add them to the pbxproj.

If you're working inside an Expo config plugin, then you can use withXcodeProject and the following code to add them:

You'll need to call the addSourceFile for every file you're adding - the swift files, the .m files, and the .h file.

After all of the above is done, you should be able to build your app. If you encounter any errors, use the help of the React Native online community, but be aware that some Xcode errors you're likely to experience might have multiple different causes, and the answer isn't always obvious.

In part 2 of this tutorial, we will guide you through integrating Native Modules for Android apps. To make sure you don't miss part 2, sign up for our monthly newsletter!

Happy coding!

Read: "What’s New in Expo SDK 50: New Features and Updates".

More insights