はじめに
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で書く方法をまとめました。