[React Native事始め完全版]「いきなりデート」のアプリをReact Nativeで開発した知見をまとめます。

この記事で説明する事

  • React Native採用に係る意思決定の話
  • atom + eslint + flowによるIDE風開発環境
  • line by lineによるプロジェクト作成方法とリリース方法
  • デバッグ方法やtips集、補助ツールの使い方

React Nativeとは

rn.png

Facebookがオープソースとして開発するReact.jsの思想の一つである「Learn once, Write everywhere」(元ネタはもちろんJavaのWrite once, Run anywhere)を体現した、Facebookが開発主体となるプロジェクトの一つで、要はJavascriptとReactフレームワーク1つでモバイルアプリ(iosとAndroid)を作れる、といった代物です。

ちなみにReact VRというJS+ReactでVRアプリを作るプロジェクト(これもFacebook本体が主導)というものあります。

同じようなクロスプラットフォームアプリ開発の手法としてCordovaやIonicなどがありますが、React Nativeはその名の通り、web viewではなくあくまでもJavaScriptランタイムでNativeのAPIを叩いて、Naitveによる描画を実現しています。

JSがNativeのコードにコンパイルされる訳でもないので、開発中においてはビルドの必要がなくHot Refreshなどが出来ます。

いきなりデートとは

Screen Shot 2017-10-07 at 1.37.29 PM.png

Screen Shot 2017-11-24 at 9.40.32 AM.png

いきなりデートは、厳しい審査に通過したハイスペック男女同士のデートをセッティングするサービスです。

顔も名前も知らぬまま、メッセージすら事前にさせず運営の予約したレストランでまずは会って話して見る事に重きをおいています。

開催場所のレストランも運営スタッフが手配するので手軽に参加できます。

今回はこのサービスをアプリ化した際に得れた知見をまとめたいと思います。

React Native、本当にいい感じに動くの?

と思われる方は

より使い心地をお試し下さい。

(宣伝です!🔥)

なぜReact Nativeなのか

いきなりデートを運営してる aisaac inc. は37siginalsやthoughtbotなどのようにエンジニアが好き好きにOSSに成果物をあげまくったり自己資本で自由に大学のラボ的なノリで様々なビジネスを回しておるため、極限まで効率を重視したくAPI開発を含めてiOS/Androidのリリースをアプリ開発経験のないエンジニア2人(1人は週末のみ)で3週間くらいでやりたいなと思っていました。(結果、出来ました🎉🎉🎉)

最初こそ「Swift勉強するか〜〜〜」と考えあぐねておりましたが、

👥 < 「React Native、いいらしいよ」
という噂をよく聞くようになったので海外の事例など含めて徹底的に調査しました。

React Nativeリリース直後にその思想こそは確認したものの、かなりその方向性には懐疑的でした。
というのも筆者は数年前にtitanium mobileに痛い目をみているので「またか」程度のものでした。

がやはりFacebookという組織の後ろ盾の大きさか、コミュニティもプロジェクトも大変よく成長しており、一ヶ月毎のRelease Noteを見る限り、健全なfixとimprovementsが確認でき「期待できるかも」と思いました。その後、様々な事例を調べfacebook/instagramは元よりsoundcloudやairbnbが採用(一部らしいが)している事も大きな追い風になりました。

パフォーマンスについてはこの記事をみて問題ない事を確信しました。

https://medium.com/the-react-native-log/comparing-the-performance-between-native-ios-swift-and-react-native-7b5490d363e2
(現在翻訳記事を執筆中です🖋)

開発した主な機能

  • Push通知🚀
  • Facebookログイン🚪
  • クレカ決済💳
  • 画像アップロード📷
  • 各種CRUD

これらについては後ほど解説を致します。

諸々構成

使っている主なパッケージ

もう、えいやとpackage.jsonから抜粋して主要なものを貼り付けちゃいます。

"react": "16.0.0-alpha.12",
"react-native": "0.47.1",
"react-native-drawer": "^2.3.0",
"react-native-facebook-login": "^1.5.0",
"react-native-fcm": "^8.0.0",
"react-native-image-picker": "^0.26.4",
"react-native-snap-carousel": "^2.4.0",
"react-native-vector-icons": "^4.3.0",
"react-navigation": "^1.0.0-beta.12",
"react-redux": "^5.0.5",
"redux": "^3.7.2",
"redux-persist": "^4.8.2",
"redux-persist-migrate": "^4.1.0",
"redux-thunk": "^2.2.0"

//dev
"babel-eslint": "^8.0.1",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-preset-react-native": "4.0.0",
"eslint": "^4.2.0",
"eslint-plugin-flowtype": "^2.39.1",
"eslint-plugin-react": "^7.1.0",
"react-test-renderer": "16.1.1",
"reactotron-react-native": "^1.12.1",
"reactotron-redux": "^1.12.0"

reduxの採用はパッケージ選択において一番の正解だったのと思っております。
httpリクエストは標準の fetch をベースに独自クラスを作って使ってます。

大雑把に

  • react-native-facebook-login ... Facebookログイン
  • react-native-fcm ... Firebase(push notification)
  • react-native-vector-icons ... アイコン
  • react-native-image-picker ... 画像アップロード
  • babel-plugin-transform-flow-strip-types, eslint-plugin-flowtype ... jsの型チェッカー、flowのためのパッケージ

って感じです。

フォルダ構成

割と普通のreduxアプリの構成だと思います。

Screen Shot 2017-10-07 at 1.37.29 PM.png

開発に使ったツール達

  • Atom + eslint + flow
    => linterと型チェッカー

  • Reactoron
    => Redux storeの中身が見れたりdispatchを手動で発行できます。

  • Xcode + AndroidStudio
    => リリース作業を考えておくと慣れておいた方がいいですね。

  • (Expo) => 結果捨てました。。m_ _m

Atom + eslint + flow でIDE風開発

今回はEditerにatomを採用しました。js開発ぽい雰囲気が出るので。
eslint というlinterライブラリとjsの型チェッカーである flow には何度も助けられました。

Screen Shot 2017-11-24 at 7.22.55 AM.png

この様に未定義変数など簡単なタイポやシンタックスエラーはeslintでエラーを吐いてくれます。
この環境はeslintの設定と atom-eslint というatomのパッケージによって達成されます。

続いてはflow+atomの挙動はこんな感じ、アプリ開発でjava/swiftに慣れている型はやはり型があった方が安心感があるでしょう。

Screen Shot 2017-11-24 at 7.53.14 AM.png

この環境はflowの設定と linter-flow というatomのパッケージによって達成されます。

Reactoron

ReactoronはReact(native以外にも使用可能)のデバッグのためのDesktop Appで、

reactotron-react-nativereactotron-redux をパッケージに追加し設定を行えばredux storeの中身やdispatch履歴を見ることが出来ます。

Screen Shot 2017-11-24 at 8.17.25 AM.png

Screen Shot 2017-10-10 at 8.15.14 AM.png

Reactoronの設定はとても簡単で、reactotron-react-nativereactotron-reduxをパッケージに追加し、

import Reactotron from 'reactotron-react-native';
import { reactotronRedux } from 'reactotron-redux';

Reactotron
  .configure({ name: 'Ikinari' })
  .use(reactotronRedux())
  .connect();
...

const store = Reactotron.createStore(
  reducers,
  initialState,
  enhancer
);

の様にstoreを作成すれば、設定完了です。

Expo

1-fTOXQ1j-0I5xe9BN98Hwwg.png

最初、create-react-native-app 使って技術調査をしていた兼ね合いもあって、
「Expo最高じゃん〜」と思って使っていました。(実際すごいです

Expoはnativeの機能を全てjsでラッピングしたExpo SDKなるものを開発しておりそれを使ったExpoエコシステムの上に乗っていると jsだけアプリ開発が完結する と思想なのですが detach と呼ばれる黒魔術を使わぬ限りnative(swift, objc, java)のコードが書けなくなってしまいます。

https://docs.expo.io/versions/latest/guides/detach.html

detachは一応試みましたが、謎なPodfileが生成されて無理やりブリッジしてる感がすごかったので諦めました。彼らもまだβ featureと言っています。

またExpoはXDEというツールやiosとandroidのexpo clientを使えばアプリを一瞬で不特定多数の実機に飛ばせるなど色々すごいんですが、そこに必要性を見出せなかったのと諸々不安定であったので(謎のメモリリークがv0.17.0ではあり、捨てたら治りました。)途中から react-native init をし直してコードを移植しました。

ただfounderがquoraのco-founderで元facebookerでチームもすごくいけてるので(linkdeinは全員チェックしましたw)今後に期待大です。頑張って欲しい。

Redux

Untitled 2.png

Reduxはfluxフレームワークの一つで、一つの大きなStoreと呼ばれる状態を一元管理するオブジェクトをdispatchと呼ばれる関数を介して変更をしその変更をViewに伝達することによってアプリケーションの動きを作っています。

Store以外からComponentをまたがる状態が変わることがないので管理がしやすい、という訳です。

筆者も実際にこの恩恵には充分預かり非常に快適なアプリ開発をさせてもらいました。

おすすめです。
https://github.com/infinitered/reactotron
というデバッグツールが大変おすすめです。

React Nativeアプリの作り方(mac編)

この部分は公式ドキュメントであったり、記事が多いので控えめに記しておきます。

nvm(nodeのバージョン管理)のインストール

https://github.com/creationix/nvm

を使用しました。

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash

でnvmをインストールし、

お使いのshell configに

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

を記述しましょう。

これで

nvm install v6.11.0 
nvm use v6.11.0

こんな感じでnodeをインストール出来ます。

yarnとreact-native-cli

better npmなポジションであるyarnを使います。
npmより高速で、きちっとしたバージョン管理が出来ます。

react-native-cli はReact Nativeアプリの作成やコンパイルをするときに使います。

npm install -g yarn react-native-cli

プロジェクトのinitialize

react-native init TestApp

でプロジェクトのinitializeは完了。

iosフォルダに入っている TestApp.xcodeproj をxcodeで開き

Screen Shot 2017-11-24 at 9.32.03 AM.png

左上の再生ボタンみたいなやつでビルドしてみよう。

Screen Shot 2017-11-24 at 9.33.46 AM.png

開発Tips

debugger

jsのdebuggerを使って作業をすることができます。
Macだと⌘+Dで開く
Screen Shot 2017-10-10 at 8.04.36 AM.png
上記画面よりDebug JS Remotelyを選択し、
ブラウザで ⌘+Shift+Cでinspectorをひらけば、ここでdebuggerが実行された文脈で処理を止め、コードを実行することで出来ます。

Screen Shot 2017-10-10 at 8.05.35 AM.png

View inspector

⌘+Dから「Show Inspector」を選択すればbrowserのinspectorのようなものが使えます。
Screen Shot 2017-10-10 at 8.09.00 AM.png

⌘+R

でソースコードの更新を反映出来ます。(Hot Reloadも可能)

機能別開発tips

機能開発のざっとしたサマリーを載せておきます。

Push通知🚀

https://github.com/evollu/react-native-fcm

を使って、fcm_tokenをアプリ側で取得し、apiを作ってuserに紐付ける形でdbに保管します。
push通知を送りたい時はfcm_tokenとfirebaseの秘密鍵を使用してfirebaseのAPIを叩くという実装にしています。(faradayなどのhttp clientで)

Facebookログイン🚪

https://github.com/magus/react-native-facebook-login

を使っています。README.mdがよく書かれているので読み込むと良いと思います。
(Androidのkeytoreまわりは結構苦労し、android経験者に助けてもらったりしました)

アプリでfb_tokenを取得し、apiを作ってdbに保管し、facebookのAPIクライアントで各種情報を取得しています。

クレカ決済💳

特にライブラリを使っていないです。fetch を使ってStripeのAPIを直接叩いています。

画像アップロード📷

https://github.com/react-community/react-native-image-picker
を使っています。README.mdがよく書かれているので読み込むと良いと思います。

各種CRUD

それぞれのComponent内の state としてフォームの情報を格納し、
actionにstateを送り、action内でAPIを値と一緒に叩き、返り値によってdispatchをしてviewに変更を加える、という流れを取っています。

リリースの仕方(ios編)

基本的にはswiftで作られたiosアプリと同じ流れの様です。簡単にまとめておきます。

Screen_Shot_2017-11-24_at_7_20_39_AM.png

本番用のschemaを作りDeviceに「Generic iOS Device」を選択します。

Screen Shot 2017-11-24 at 8.20.56 AM.png

Product から 「Archive」を選び諸々設定をします。

あとは勝手にitunes connectにあげてくれるのでTestflightなりリリース申請なりしましょう💪

締め

どうだったでしょうか。一部駆け足となるところもありましたが、是非、React Native採用の後押しになればと思います。また弊社(aisaac inc.) はReact Nativeによるアプリ開発やコミュニティ作りに力を入れています。是非アプリ制作のご相談や興味のある技術者の方はお声がけお願いします!m_ _m