potpro (ぽとぷろ)
Full-stuck engineer(Not Full-stack)
JS/PHP/Go/Docker/Nginxなど。技術または趣味寄りの発信ブログです。
全 85 記事React Nativeネイティブモジュール(Swift/iOS)を使う
React Nativeネイティブモジュール(Swift/iOS)を使う
potproject.net Advent Calendar 20169日目の記事です。
で、とりあえず実機で動くかの確認は取れました。
で、今回は、React Nativeとネイティブコードの連携をやってみたいと思います。
React NativeはiOSやAndroidを共通のJavascriptで書いてマルチプラットフォームでしかもネイティブに動くよ!というのがウリです。
しかし、当然ながら、SwiftやObjective-Cを使うようなものも必要になります。カメラとかプッシュ機能。
まあメジャーなものは用意されてる場合もあるんですが、マイナーなものは無かったりするので、
自分で作ってね!ってことでネイティブモジュールという機能で補完できるようになってます。
Cordovaを思い出す。しかしこっちは完全ネイティブなのだ。
このあたりを参考にしました。しかしまあやっぱり例によってSwift3.0なので結構コード変えてたりもします。
React NativeでNative機能をSwiftで書いて使うには
Native Modules
Objective-Cは全く分からないのでSwiftです。でもブリッジしなくてはならないので多少はObjective-Cは避けられないんだなあこれが。
:原則、React NativeはネイティブモジュールにSwiftを使うように設計されていません。生成されたプロジェクトもObjective-C用で生成されます。
なので、使うにはObjective-CとSwiftを連携させる必要があります。
swiftでモジュールを作成
まずは、モジュールを作成します。ちなみにこれだけだとまだ動きません。
端末の時間を取得してAny(Dictionary)型でコールバックを返します。
どうやらReact Nativeのjavascriptにデータを受け渡す際は必ずcallbackなのかな。
ちなみにPromiseも使えます。
** ReactNativeModule.swift **
import Foundation
@objc(ReactNativeModule)
class ReactNativeModule: NSObject {
@objc func callbackMethod(_ callback: RCTResponseSenderBlock) -> Void {
// システムのカレンダーを取得
let cal = Calendar.current
// 現在時刻のDateComponentsを取り出す
var dataComps = cal.dateComponents([.year, .month, .day, .hour, .minute], from: Date())
let object = [
"year":dataComps.year!,
"month":dataComps.month!,
"day":dataComps.day!
]
callback([object])
}
}
配列で返しても大丈夫なの?と思いでしょうが、ちゃんとReact Native側はjavascript Object型で受け取ってくれます。優秀です。 callbackMethodの第一引数が無名関数がなっているのは、このあたりの問題から。認識してくれないのです。Swift3.0での変更点となります。 Got “is not a recognized Objective-C method” when bridging Swift to React-Native - stackoverflow
Objective-Cでエクスポートする
** ReactNativeModuleBridge.m **
#import "RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(ReactNativeModule, NSObject)
RCT_EXTERN_METHOD(callbackMethod:(RCTResponseSenderBlock)callback)
@end
実際はこのObjective-Cが読み込まれます。これが上で書いたSwiftコードの橋渡しになります。
Objective-Cの文法は相変わらず割と理解できていない。
** testreactnative-Bridging-Header.h **
#import "RCTBridgeModule.h"
RCTBridgeModule.hというObjective-CのコードをSwiftで読み込むために設置。 このあたりに関してはググるといっぱい出てくるため割愛。
React Native側のソースはこんな感じ。画面の更新もしたかったのだが、結構時間掛かりそうで・・・ただログ出すだけ。
** index.ios.js **
import React, { Component } from 'react';
import {
NativeModules,
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
var nm=NativeModules.ReactNativeModule;
nm.callbackMethod(function(res){
console.log(res);
});
これでデバッグ画面からログが確認できました。
ちゃんと{"year":2016,"month":12,"day":9}と出てきます。Any型も受け渡せるのは楽でいいですねえ。