React Native — Native Modules With Swift

Richard Petrov
Nov 3 · 4 min read

Introduction

Working with Native Modules and accessing iOS native libraries may seem like a daunting task, but it’s not. It may take some time getting used to, but it’s not as difficult as you may think. Just a fair warning you will have to work with Objective-C and Swift.

My journey into native modules began at work where I volunteered to create a module for React Native that interacts with a Swift SDK. This tutorial won’t be related to my project at work, but it will be a module that will play a .wav file. I will show you how to create a module that will take advantage of the AVAudioPlayer Library in iOS.

Basic Setup

Let’s get started creating our native module with a sample project we can work with.

The first step is to get the create-react-native-module tool that is used in the React Native docs.

Yarn global add creat-react-native-module

Creating Our Project

After we installed the create-react-native-module it’s time to create our native module project.

Create-react-native-module --package-indentifier io.myaudiolibrary ---generate-example AudioHelper.

You will now have a project directory named react-native-audio-helper with an example subfolder with another project.

The root folder react-native-audio-helper is the native module we’ll be creating, and the example folder is the project we’ll use to access the native module.

If you ran the example project without any modifications it will look like this:

Bridging Objective-C and Swift

Lets get started with creating the bridge between Objective-C and Swift.

Go into the react-native-audio-helper/ios folder and open the code project called AudioHelper.xcodeproj using XCode.

First things we should do is insert #import <React/RCTBridgeModule.h> at the top of AudioHelper.m.

We are going to delete the AudioHelper.h file but we want to keep the RCTBridgeModule header.

Go ahead and delete AudioHelper.h and click on the “Move to trash button”.

It’s time to create a swift file that creating a bridging header file which will expose the Objective-C files to Swift. Apple provides a decent explanation on how to do that here.

React Native Objective-C Bridging
React Native Objective-C Bridging

File->New->Swift and call it AudioHelper.swift and click on Create bridge header which will create two new files:

AudioHelper.swift

AudioHelper-Bridging-Header.h

Copy and paste this code into the AudioHelper.swift:

var player: AVAudioPlayer?@objc(AudioHelper)
class
AudioHelper: NSObject {

@objc(playSound:)
func
playSound(url: String) {
guard let url = URL.init(string: url) else { return }
do {
if #available(iOS 10.0, *) {
try AVAudioSession.sharedInstance()
.setCategory(.playback, mode: .default)
} else {
// Fallback on earlier versions
}
try AVAudioSession.sharedInstance().setActive(true)
/* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue) /* iOS 10 and earlier require the following line:
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
}

If you are not familiar with Objective-C or Swift the key to bridging both languages is using the @objc syntax in your swift code. Placing @objc before a swift class or function exposes it to the Objective-C side of things.

This is what the AudioHelper.m should look like:

@interface RCT_EXTERN_MODULE(AudioHelper, NSObject)   RCT_EXTERN_METHOD(playSound:(NSString *)url)@end

The RCT_EXTERN_MODULE and RCT_EXTERN_METHOD macros expose the AudioHelper swift class and playSound function to React Native and Javascript.

After saving the project we’ll go into the example folder and reinstall the new changes:

rm -rf node_modules && yarn install

This will update our changes we did in the AudioHelper module to the example project where we will test it out.

Bridging Objective-C and JavaScript

The Javascript portion is pretty straight forward if you are already use to React Native.

import React, { Component } from ‘react’;
import { Platform, StyleSheet, Text, View } from ‘react-native’;
import AudioHelper from ‘react-native-audio-helper’;
export default class App extends Component<{}> { componentDidMount() {
AudioHelper.playSound(“/Directory/To/Some/Mp3/Music.mp3”);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>☆AudioHelper example☆</Text>
</View>);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: ‘center’,
alignItems: ‘center’,
backgroundColor: ‘#F5FCFF’,
},
});

What I did here was minimize the example project that was auto generated to work with our App.

The most import parts of the code is the import statement:

import AudioHelper from react-native-audio-helper;

And calling the native function call to play the audio file:

AudioHelper.playSound(“/Directory/To/Some/Mp3/Music.mp3”);

Make sure you have an audio file you can play to test the app out. I just used one of my old tracks I had on my hard drive.

Thoughts

This tutorial is just the first steps into creating React Native — Native Modules. It’s enough to get you started, but it’s limiting since it allows you to only make calls from Javascript->Swift. I plan to write more tutorials on native modules including topics like Callbacks, Events, and Threading.

Richard Petrov

Written by

Mobile Engineer, React Native & iOS

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade