← Back to Blog
react react-native ios native modules

React Native: 3rd party dependency with View Modules

I'll start this blog post by saying that I have gained tremendous respect for my colleagues who use React Native day in and day out. The sheer number of tools needed to run and compile a single React Native project is truly overwhelming.

Introduction

The Promise

React Native promises to significantly reduce the workload needed to produce a multi-platform app. With just a single JavaScript project, an individual can create both an iOS and Android app that offer consistent behavior and appearance.

The Reality

When tasked with building custom experiences, like the one my client required, you quickly realize that three integrated development environments (IDEs) must run side-by-side to get the app functioning.

Managing attention across three distinct contexts—iOS, Web, and Android—is already a challenge. But then, you're hit with platform-specific errors. These errors are not only obscure but are further complicated by the lack of robust debugging tools for React Native.

The Problem

We're attempting to construct what's termed as a React Native Native Component iOS. This leverages a native Swift XCFramework named Wowza Flowplayer Apple SDK, which I developed.

The Wowza Flowplayer Apple SDK is a fully integrated video player that supports various media types, including VODs and livestreams. Despite its compact size and customizability, it operates seamlessly, demanding minimal device resources thanks to its efficient architecture.

Step 1: Setting Up the Project

Starting a project using the react-native-cli and manually linking the Native Module can quickly become chaotic due to the extensive linking required.

Instead, I recommend utilizing the react-native-builder-bob CLI from Callstack. This tool is incredibly user-friendly:

npx create-react-native-library@latest my-library

Answer the questions of the CLI:

? What is the name of the npm package? › <NAME>
? What is the description for the package? › <DESCRIPTION>
? What is the name of package author? › <DEVELOPER>
? What is the email address for the package author? › <EMAIL>
? What is the URL for the package author? › <URL>
? What is the URL for the repository? › <GIT_URL>
? What type of library do you want to develop? › Native view
? Which languages do you want to use? › Kotlin & Swift

All that remains is for us to cd into our project root and install the dependencies:

cd my-library
yarn

Step 2: Exploring the Code

JavaScript

Upon opening the src directory, you'll encounter the TypeScript code:

import {
  requireNativeComponent,
  UIManager,
  Platform,
  type ViewStyle,
} from "react-native";

type AwesomeLibraryProps = {
  color: string,
  style: ViewStyle,
};

const ComponentName = "AwesomeLibraryView";

export const AwesomeLibraryView =
  UIManager.getViewManagerConfig(ComponentName) != null
    ? requireNativeComponent<AwesomeLibraryProps>(ComponentName)
    : () => {
        throw new Error(LINKING_ERROR);
      };

iOS

Let's look at the iOS side. The Bridging-Header file acts as an Objective-C header, creating a bridge between our Swift code and Objective-C:

#import <React/RCTViewManager.h>

The ViewManager.m file exports our view manager:

#import <React/RCTViewManager.h>

@interface RCT_EXTERN_MODULE(AwesomeLibraryViewManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(color, NSString)
@end

And the actual Swift implementation:

@objc(AwesomeLibraryViewManager)
class AwesomeLibraryViewManager: RCTViewManager {

  override func view() -> (AwesomeLibraryView) {
    return AwesomeLibraryView()
  }

  @objc override static func requiresMainQueueSetup() -> Bool {
    return false
  }
}

class AwesomeLibraryView : UIView {

  @objc var color: String = "" {
    didSet {
      self.backgroundColor = hexStringToUIColor(hexColor: color)
    }
  }
}

Step 3: Incorporating 3rd Party Swift Dependencies

We'll leverage CocoaPods. Open the .podspec file and add the dependency:

# Set FlowplayerSDK dependency
s.dependency "FlowplayerSDK", '~> 4.1.0'
s.dependency "GoogleAds-IMA-iOS-SDK", '~> 3.19.1'

Then run:

yarn clean
yarn

If you need to support iOS 14+, update the Podfile:

min_ios_versions_supported = ['14.0', min_ios_version_supported]
index_of_max = min_ios_versions_supported.each_with_index.max_by { |number, _| number.to_f }[1]
platform :ios, min_ios_versions_supported[index_of_max]
prepare_react_native_project!

Step 4: Utilizing our 3rd Party Dependency

Now we can import and use our dependency:

import FlowplayerSDK

// Add the code for setup here

Note: To get intellisense when developing React Native iOS Modules, open example/ios/AwesomeLibraryExample.xcworkspacePodsDevelopment Podsreact-native-awesome-library. Edit all your files from here as the Example workspace has the context of all libraries and frameworks.

Conclusion

It's been quite the journey, plagued with platform-specific intricacies, just to get our dependency to load in a manner that's update-friendly via the CLI and CocoaPods. It's my sincerest wish that this blog post spares any other developer the same strenuous path I've had to traverse.

GitHub repo for reference: github.com/br3akzero

Cheers to perseverance and the love of code,

Break Zero.