React Native + FirebaseでiOS & Androidアプリを開発してリリースしました
React Native + Firebase で「TouchLife」
という家計簿アプリを開発して、
iOS、Android アプリとしてリリースしました。
今後のサービス開発にも、とても良い経験となりましたので、
どんな技術を使ったのかなどご紹介したいと思います。
TouchLife とは








お金の支出と収入の管理を本格的にしたい方のための家計簿アプリです。
・日毎に支出と収入の状況を分析して教えてくれる前月同日対比
・支出順で表示される支出ランキング
・調子が良い、悪いがひと目で分かるバランスシート
ビジネスのシーンで使うような本格的な分析の機能を、出来るだけ分かりやすくなるように考えて開発しました。 普段は自分もエンジニアとして会社に所属しているので、その合間で開発を進めた感じです。 友人と 2 名体勢で、友人が企画 + デザイン、自分がエンジニアリングを担当しました。
以下、技術メインで紹介できればと思います。
使った技術
- React Native(Expo)
- Firebase
- React Navigation
- redux + thunk
- Sentry
- Google Analytics
React Native(Expo)


メインはReact Native + Expoです。
これらを使うことで iOS/Android アプリを App Store と Google Play にリリースするのに必要なipa、apkファイルを生成することが可能
です。
通常は ipa や apk を作るのに、Xcode や Android Studio で Swift や Kotlin で書きつつ開発するのがアプリ開発のスタンダードだと思いますが、React Native や Expo を使うことで画面のレイアウトからロジックまでを、React や CSS(に近しいもの)で作ることができます。 また完成したアプリは WebView で表示するハイブリットなものではなく Objective-C や Java に変換されます。 ネイティブに動作するのでパフォーマンスもネイティブで開発したアプリと同等になるのがメリットです。
最初は Expo を使わず公式の React Native のみで開発していましたが、React Native のバージョンアップに追従させる時や何か特別なことを入れようとする度にエラーとなってしまう事が多く、機能の開発よりそのエラーの解決に労力が割かれてる感がずっと気になっていました。
これはいかんということで Expo で 1 から作り直したのですが、この開発体験がびっくりするぐらい良かったです。 基本 Expo のレール上の実装になるので機能は Expo で提供されているものに制限されるデメリットはありますが、その分エラーになる事がほとんどなくなり、結果的にそれまでの 2 倍ぐらいの開発スピードになったと思います。 今回のアプリの要件が Expo の提供範囲内で十分開発可能だったことも Expo 移行の理由でした。
また今回は友人とリモートでやりとりしながらの開発だったんですが、Expo の場合、Expo Client の iPhone アプリを通じて遠隔地でもビルドなしで iPhone の実機でさっと確認可能で、これが大変役に立ちました。
Firebase

ユーザー認証やデータベースへの保存の仕組みが必要で、認証の仕組みが予め備わっていてモバイルアプリに特化しているFirebaseを使う事にしました。
主に使った機能は、Authentication、Firestore、Functions, Hosting
の 4 つです。
Authentication
- メールアドレス + パスワード認証
- Facebook, Google, Twitter 認証
- 匿名ログイン
を実装しました。
特にユーザーの入力したパスワードはFirebase側のみで管理されて自前で管理しなくてよくなる
(開発者も知る事ができない)ので、よりセキュア + DB に encrypt して保存のような実装もいらなくなるので、その分をメインの開発に時間を割く事が出来ました。
FacebookとGoogle認証に関しては、Expo のドキュメントに沿って実装することで問題ありませんでした。 Twitter 認証に関しては Expo のドキュメントには記載はなさそうで、少し難易度高めでした。 ただ、こちらのサンプルは参考になりそうです。
匿名ログインは比較的簡単に実装可能でした。 こちらのドキュメントが参考になります。 Firebase Authentication の素晴らしい機能の 1 つだと思います。
Firestore
ユーザー情報とそれに紐づく支出、収入のデータの DB 保存が必要だったので、Firestore を使いました。
usersコレクションにユーザーごとのデータ、その中に支出、収入のサブコレクションを持つ構成
にしました。
無料の範囲内で利用できています。
ただ、これを超えないとユーザーがあまりいないかあまり使ってないという事なので、これを超えるというのが 1 つの目標になると思います。
そして超えるようになると、Firestore の設計にも関わってきますが、通常は Admob などの広告収入で超えた分をまかなえてくると思われます。
Functions
お問い合わせすると、その内容を Gmail に送信する必要があったので Functions を使って実装しました。 内部でNodemailerを使っています。下記の記事が非常に参考になりました。 Vue.js + Firebase functions でお問い合わせフォームを作成する
Hosting
主に利用規約、プライバシーポリシーの静的ページの為に使いました。 Expo の WebView を使って、アプリ内から参照するようにしています。 またメール認証した後にアプリに戻すリダイレクトが必要だったため、リダイレクト専用の html ファイルも配置しています。
ゆくゆくはランディングページにも利用する事になりそうです。 その際は現行のフロントエンドのベストプラクティスが詰まってるNuxtのgenerateで作るのが良いかなと思ってます。(このブログも nuxt generate + markdown です) -> 2020 年 5 月現在、Next.jsも有力な候補の 1 つとなりそうです。
React Navigation
ルーティングとナビゲーションはReact Navigationで実装しました。 最初はreact-native-router-fluxを使っていましたが、このモジュール自体が React Navigation をベースに作られていて React Navigation のドキュメントがしっかり準備されていたので、途中から React Navigation に変更しました。 これから始めるなら React Navigation で良い印象です。
redux + thunk
状態管理はreact-redux また DB へのアクセス時に非同期通信が必要なので、ミドルウェアはredux-thunkを入れました。 redux-sagaの選択肢もありましたが、thunk の方がなじみがあったのでこちらにしました。
Sentry

バグ検知は Expo で公式にサポートされているSentryを導入。 ユーザーの端末でエラーが起きると Gmail, Slack に通知が飛ぶようになっています。 sentry-expoを使っていて、今のところ無料範囲内で利用できています。
Google Analytics
アプリのインストール数などは App Store Connect のアナリティクスでも確認できますが、具体的な時間帯や詳しい情報も欲しかったので Google Analytics を導入しました。 expo-analyticsを使っています。 さらに踏み込んだ分析をする場合は、Amplitudeなどを導入すると良さそうです。
使用したライブラリ一覧
以下、TouchLife で使った主なライブラリ一覧です。
date-fns

5月1日(水)
のような日本語にフォーマットされた日付が必要だったので使いました。
UltraDate.js

給料日が土日祝の場合はその前の平日を取得する
などが必要で、そちらが取得できる UltraDate.js を使いました。
ちゃんと実装すると面倒な祝日やうるう年の計算など、Date オブジェクトを便利に拡張したライブラリです。
react-native-svg + d3-shape

円グラフの為に使いました。
最初はreact-native-pie-chartを使っていたのですが、円グラフをアニメーションさせようとすると react-native-pie-chart だと難しそうでこちらを使いました。(アニメーションしない円グラフだけの表示なら react-native-pie-chart でも十分だと思います)
d3-shape
で円のデータを作成、それをreact-native-svg
で描画する流れです。
下記の記事が参考になりました。 Pie animation in React Native using SVG
formik + yup

メールアドレスやパスワードなどフォームのバリデーションが扱いやすくなるので使いました。React の公式ドキュメントでも紹介されているものです。
別の選択肢だとredux-formもあり、こちらはフォームの状態を redux の store に保存するようですが、React コミュニティの一般的な見解だとフォームの状態を redux で管理しない方向のようで、formik
やreact-final-formを使うのが良いとのことでした。
native-base

主にフォームのセレクトボックスで使用。 最初セレクトボックスは、react-native-picker-selectを使っていたのですが、Android で見た時に表示がおかしかったので、安定していた native-base に切り替えました。
react-native-calendars

カレンダーの実装に使っています。
monthFormat={"yyyy年MM月"}
などで日本語のフォーマットでカスタマイズ可能なのも良かったです。
react-native-easy-toast

マイページなどユーザー情報を変更した時の、成功、失敗をユーザーに知らせる目的で使いました。 表示する位置や色は自由にカスタマイズ出来ます。
react-native-keyboard-aware-scroll-view

画面の下の方に Input 要素があると、キーボードが下から出てきた時に入力している部分が隠れてしまい何が入力されているのか分からない問題
があったのですが、その部分が隠れないようにスクロールしてくれるモジュールです。自分で実装するとそれなりに大変そうだったので助かりました。
react-native-keyboard-aware-scroll-view
react-native-modal

シンプルなモーダルです。 簡単に表示、非表示が出来て、スタイルもカスタマイズ可能です。
react-native-scrollable-tab-view-universal

タブ切り替えが必要な箇所に使いました。
スワイプ操作にも対応しているので UX も良い印象です。
最初は、react-native-scrollable-tab-viewを使っていましたが、ScrollViewの中で使おうとするとAndroidだけ中の要素が表示されない不具合
があり、それが解決されている universal を使うことにしました。
universal もreact-native-scrollable-tab-view
を Fork してるものになるので、この不具合が修正が改善されれば、react-native-scrollable-tab-view
で良いと思います。
react-native-scrollable-tab-view-universal
react-native-snap-carousel

オープニングやグラフのカルーセルに使いました。
次や前の月のグラフもちょっと見せるUIにしかった
ので、それが可能だったこちらを使いました。
react-native-walkthrough-tooltip

ツールチップの表示に使いました。
アプリの使い方を伝える最初のチュートリアルにも使えそうです。
ツールチップが画面外にはみ出ないように、ライブラリ側で位置を自動計算
してくれて使う側がそこを意識しなくてよいのが良かったです。
react-native-walkthrough-tooltip
npm-run-all
実践 Expoに書いてあって初めて知ったんですが、これが便利でした。
yarn add -D npm-run-all
後に、package.json のscripts
を下記のように書いておいて、
"scripts": {
"build:ios": "npm-run-all -s ios:*",
"ios:run": "expo build:ios --non-interactive",
"ios:file": "mkdir -p .build && wget \"$(expo url:ipa)\" -O .build/app.ipa",
},
yarn build:ios
すると、ios:run
やios:file
などのios:*
の scripts が順番に実行される、というものです。
これで ipa ファイルが.build/app.ipa
に生成されるので、後は fastlane を使って App Store Connect にデプロイ → 実機確認 → 申請 → 公開 という感じで無事リリース出来ました。
実践 Expoは開発の途中から Kindle 版を買ったんですが、特に Expo を使ったリリース方法 + Analytics や Sentry の設定方法も載っていて、とても為になりました。Expo で開発する場合はオススメの一冊です。
まとめ
React Native 良いですね。 開発途中で Android で実機確認したんですが、最初に Android で iPhone と同じように動作した時は感動しました。
また途中から Expo で作り直したのも良かったなと思っています。
最初は Expo って公式の React Native からちょっと外れたニッチな開発のように感じて、公式から外れるのはどうかな的な感覚があったのですが使ってみると使いやすくて、必要ならejectしていつでも公式のReact Nativeに戻せる
というのも移行した理由になりました。
React Native で作られたアプリが実際にどんなものなのか、是非一度体験して頂ければと思います。 最後まで読んでいただき、ありがとうございました 👍