まずは、ネイティブアプリとのインテグレーションをやっていく。僕は、iOSのエンジニアなので、まずはiOSから。そのうち、Androidもやりたいと思っているが、Androidはメルカリの人がよいチュートリアルを書いている。
ReactNativeのインテグレーションは、公式のドキュメントが参考になるので、それを見ながら進めていく。
ReactNativeプロジェクトを作る
まず、ReactNativeプロジェクトを作成する。
react-native init YOUR_APP_NAME
これで、ReactNativeプロジェクトが作成される。動かしてみたい場合は、 react-native run-ios
とすれば良い。ReactNativeが作ってくれる、デフォルトのアプリケーションが立ち上がる。
既存アプリで置き換える
さて、既存のアプリでiosフォルダを置き換えよう。もし、git submoduleにしても良い。その場合は、iosフォルダを削除して、
git submodule add GIT_ADDRESS_HERE ios
git submoduleはそれはそれでめんどくさいので、単純に置き換えるほうが便利かなとは思っている。
既存アプリに導入する
iOSの既存アプリにReactNativeを導入するには、cocoapodsを使うのが楽だ。下記のようなPodfileを用意して、pod install
する。
target 'YOUR_APPLICATION_NAME' do pod 'React', :path => '../node_modules/react-native', :subspecs => [ 'Core', 'CxxBridge', 'DevSupport', 'RCTText', 'RCTNetwork', 'RCTLinkingIOS', 'RCTImage', 'RCTWebSocket', 'RCTAnimation', ] pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' end
これで、準備は整った。ViewControllerにStyoryboadからIBActionをつなげて、下記のよう書く。以下はモーダルで表示する例だ。ViewController.mで作業していることを想定している。
#import <React/RCTRootView.h> - (IBAction)actionOfShowApp:(id)sender { NSURL *jsCodeLocation; jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"YOUR_APP_NAME" initialProperties:nil launchOptions:nil]; UIViewController *vc = [[UIViewController alloc] init]; vc.view = rootView; [self presentViewController:vc animated:YES completion:nil]; }
これで動かすと、既存アプリにReactNativeが導入できる。動かすときは、
npm run start
react-native run-ios
とする必要がある。ReactNative単体でアプリを作っているときは、react-native run-ios
だけでnpm run start
は自動的に動き、パッケージマネージャが動いてくれる。しかし、ハイブリッドにするとこれが同時に動いてくれないみたいなので、別々に動かす必要がある。なので、react-native run-ios
はXcodeのビルドでも良い。
ReactNativeとネイティブを繋ぐ
さて、モーダルで表示すると、戻れなくなる。ので、Native Moduleを使って、モーダルを閉じる。
まずは、ViewController.hを編集する。
#import <React/RCTBridgeModule.h> @interface ViewController : ViewController<RCTBridgeModule> @end
次に、ViewController.mを編集する。注意点は、UIの変更になるので、メインキューを使えるようにしていること。また、RCT_EXPORT_METHOD
の中でdismissViewControllerAnimated
を直接呼びたいのだが、どうもうまく動かないので、NSNotificationCenter
でイベントを飛ばして、ViewControllerでObserveしてから、dismissViewControllerAnimated
するようにしている。
NSString *const DISMISS_MODAL = @"DISMISS_MODAL"; RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(dismissEvent) { dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:DISMISS_MODAL object:self userInfo:nil]; }); } + (BOOL)requiresMainQueueSetup { return YES; } - (void) dismissModal{ [self dismissViewControllerAnimated:YES completion:nil]; } -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModal) name:DISMISS_MODAL object:nil]; } -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [[NSNotificationCenter defaultCenter] removeObserver:self]; }
次に、ReactNative側からネイティブ側でExportしたメソッドを呼び出す。App.jsを変更する
import { Button, NativeModules } from 'react-native'; export default class App extends Component { render() { return ( ... <Button onPress={() => { NativeModules.ViewController.dismissEvent() }} title="Dismiss Modal" color="#841584" /> ... ) } }
これで、ネイティブ側でExportしたメソッドを呼び出すことができ、モーダルを閉じることができる。
以上で、ハイブリッドアプリへの第一歩が踏み出せた。とりあえず、固定のViewをReactNativeで作って表示したいのようなような場合には使えるだろう。