はじめに
iOSのネイティブAPIにアクセスするために、ReactNatveにはNative ModuleというAPIが用意されています。
今回は、Swiftでネイティブモジュールを実装する方法をまとめます。
ReactNativeプロジェクトの作成
まだプロジェクトがない場合は、作成します。
npx react-native init myApp
XCodeでSwiftファイルを作成する
ios/myApp.xcodeprojにあるプロジェクトをXCodeで開きます。
NativeModulesフォルダを作成します。(任意)
NativeModulesフォルダ内に.swiftファイルを作成します。

Objective-C Bridging Headerを作成する
.swiftファイルを作成すると、XCodeからObjective-C Bridging Headerを作成するかどうか聞かれるの、作成する。
このファイルは、名前の通りSwiftファイルとObjective-Cファイルをブリッジするものです。
ファイル名は変えてはいけません。
以下のように、Objective-C Bridging Headerに追記します。
myApp-Bridging-Header.h
// myApp-Bridging-Header.h
#import"React/RCTBridgeModule.h"
メソッドを実装する
手始めに、最も簡単なネイティブモジュールを実装してみましょう。
カウンターの値を変化させます。
Counter.swift
import Foundation@objc(Counter)
class Counter: NSObject {
private var count = 0
@objc
func increment() {
count += 1
print("count is \(count)")
}
}
メソッドをReactNativeから扱えるようにする
実装したメソッドをReactNativeから扱えるようにObjective-Cのファイルを作成します。
先ほど作成したSwiftファイルと同じ名前で、同ディレクトリに作成します。

作成したファイルには以下を追記します。
Counter.m
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(Counter, NSObject)
RCT_EXTERN_METHOD(increment)
@end
RCT_EXTERN_METHODについて
RCT_EXTERN_METHODに記述したメソッドは、ReactNativeで使用することができます。
メソッドに引数がない場合は、以下のように記述します。
RCT_EXTERN_METHOD(methodName)
引数がある場合は、以下のように記述します。
RCT_EXTERN_METHOD(
methodName: (paramType1)internalParamName1
)
例えば、incrementメソッドに引数が必要な場合swiftファイルは以下のようになります。
@objc
func increment(_ num: Int) {
...
}
対応するRCT_EXTERN_METHODは以下のようになります。
RCT_EXTERN_METHOD(
increment: (Int)num
)
ReactNativeから呼び出す
NativeModulesをインポートし、クラス名.メソッドで呼び出すことができます。
import { NativeModules } from 'react-native'
NativeModules.Counter.increment(1));
Event Emitterを扱う
iOSネイティブ側で起こるイベントをSunscribeしたい時には、RCTEventEmitterを使用します。
Objective-Cのファイルに、以下を記述します。
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
@interface RCT_EXTERN_MODULE(Counter, RCTEventEmitter)
さらに、ブリッジファイルにも追記します。
CounterApp-Bridging-Header.h
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
Swiftファイルには以下を実装します。
sendEvent: イベント名と、その内容を記述supportedEvents: ReactNative側でリスナーを貼る時のイベント名を記述
@objc(Counter)
class Counter: RCTEventEmitter {
@objc
func increment() {
count += 1
print("count is \(count)")
sendEvent(withName: "onIncrement", body: ["count": count])
}
override func supportedEvents() -> [String]! {
return ["onIncrement"]
}
}
ReactNative側で、イベントリスナーで待ち受けます。
import {
NativeModules,
NativeEventEmitter
} from 'react-native'
const CounterEvents = new NativeEventEmitter(NativeModules.Counter);
CounterEvents.addListener(
"onIncrement",
(res) => console.log(res)
);
NativeModules.Counter.increment();
[警告] Module requires main queue setupへの対処
以下のような警告が出ることがあります。
Module requires main queue setup
これは、モジュールの処理をメインスレッドで行うか、バックグラウンドで行うか設定しなさいという警告です。
以下のように記述し、警告を消すことができます。
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
trueを返す: メインスレッドで処理falseを返す: バックグラウンドで処理
まとめ
ネイティブモジュールをSwiftで書く方法をまとめました。