この記事は React Native Advent Calendar 2020 の 19 日目の記事です。

はじめに

PIAZZA 株式会社でエンジニアをしている奥澤です。 2016 年 10 月に React Native で開発した Android 版 ピアッザ をリリースしました。

2017 年より、ReactNative の Advent Calendar に参加させて頂いております。

毎年、1 年の振り返りをまとめていたのですが、今回は 12/14 にリリースした大型アップデートで苦労した点を中心に共有したいと思います。

前提条件として

という環境での Tips …


この記事はReact Native Advent Calendar 2019 の 7 日目の記事です。

はじめに

PIAZZA 株式会社でエンジニアをしている奥澤です。 2016 年 10 月に React Native で開発したAndroid 版 PIAZZA(ピアッツァ) をリリースしました。

一昨年昨年、に続いて 1 年の開発の振り返りをしたいと思います。

一見、自分には関係ない…みたいな所も、何かトラブルがあったときの手がかりになりうる事が結構あると思うので、何かのお役に立てれば幸いです。

リリース回数

2018/12〜2019/11 の 1 年間で、24 回でした。昨年は 18 回だったので結構増えました。 0.59.9 へのアップデートを他のメンバーが手伝ってくれたのが大きかったです。

targetSdkVersion 26 での push 通知対応

使用ライブラ …


この記事はReact Native Advent Calendar 2018 3日目です。

PIAZZAという地域SNSのandroidアプリをReact Nativeで開発しています。

昨年の投稿から1年間の開発メモというような位置づけです。

開発について

  • ReactNativeによるandroidアプリの開発。
  • 開発メンバーは自分ひとり。
  • apiも自分で書く。
  • コード規模: 約26000行

この1年

  • リリース回数: 18回(2017/12〜2018/11)

以下、機能追加やupdate時のハマり等を項目毎に。

react-native-photo-view

画像の拡縮にreact-native-image-zoomを使っていたが、ある不具合によりreact-native-fcmのupdateが必要 → sdkやbuildtools等のupdateが必要 → 他のnative …


https://medium.com/airbnb-engineering/react-native-at-airbnb-f95aa460be1c

part2

  • reduxの学習曲線が緩やか
  • RNをforkして使っていた。2年間でそこへ約50commit。結果upgradeが苦しくなる。
  • 型についてはflowはエラーメッセージがわかりにくい、TypeScriptは調査中。
  • 型が無いとリファクタリングが辛い。
  • androidがJSCoreを持っていないため、ios/androidで動作に差異があるケースがあった。
  • マルチプラットフォームに対応したOSSは全てのプラットフォームに同等の知識がある人間が作成してるわけではない。(よって不具合も多い。)
  • クラッシュレポートにBugsnagを使用。
  • クラッシュ時に、ReactNativeとネイティブ間でスタックトレースがジャンプできなくてデバッグが困難。
  • Native Bridgeでjsから整数がくる際、多くの場合は文字列として渡ってくる。iosは単なるエラーでもandroidでクラッシュする場合もある。
  • ランタイムの初期化に時間がかかる。
  • 最初のレンダリングに時間がかかるので、android/ios双方別の方法で対処をいれている。
  • アプリサイズの増大も無視できないレベルである。
  • FlatListはAndroidのRecyclerViewやiOSのUICollectionViewには及ばない。
  • RN本体が一時期RN0.16betaを使用していたため、upgradeできなかった。このため、インフラストラクチャに大きな損害があった。

part3

  • ios/android/react全てに優秀なエンジニアはまれ。よってそのプラットフォームに経験の浅いエンジニアがデバッグする場合、困難な場合がある。
  • Airbnb = 100% ReactNativeというイメージのせいで、ios/androidのネイティブエンジニアが応募をためらう結果となった。
  • ハイブリッドアプリ開発は難しい。stateの共用、チームの分割/運用、テスト、リソースの雇用/運用…
  • ReactNative/ios/androidの3つの開発環境を学習し、全て最新を維持するのは時間がかかる。
  • 多くのエンジニアはどちらか1つのプラットフォームをメインに開発する。だが、それだとQAで問題/遅延が発生するため、間違いだった。
  • コードベースがネイティブとReact Nativeに分割されると、コードが断片化する。
  • ios/anroidに比べると、教育/トレーニング(のリソースが限られているため)に投資が必要

part4

  • 3つのプラットフォームでのコードの共有が思ったほどうまくいかなかった。
  • ビルド時間は劇的に向上するものの、デバッグ等で時間がかかってしまう。
  • 今年末までに、トラフィックの多い画面の大半をnativeへ移行する。

part5

  • Server-Driven Rendering の具体的な仕組みが気になる。画面(UI)の定義をクライアントに送って画面生成かな?
  • 状態を維持しつつjson駆動の画面遷移を実現。
  • Lonaを使用した完全なカスタムコンポーネント。
  • Epoxyをandroid, ios双方で使用している。
  • MvRxという新しいフレームワークを使っている。今後オープンソースを計画中。
  • iosも同様のフレームワークに取り組んでいる。
  • ビルド速度の改善についても、色々やって目処がついている。(良くわからないが、依存関係整理してプロジェクト分けてビルドしてる?)

感想

非常に読み応えのある内容だった。

ReactNativeへの印象は 個人によってもそうだが、会社(のステージ)や事業によっても当然変わる。また、使い方(web含めたマルチ, ios/adnroidマルチ, ios or android)によっても変わる。

自分の場合は、以下の要件が重なってRNを使うに至った。

  • AndroidStudioを使いたくない(emacsから出たくない)
  • ホットリロードが最高
  • Reactを使ったことがあった
  • 自分ひとりで開発/自分で技術を選べた
  • RN自体の仕組みに興味があり、使ってみたかった
  • androidのみの使用のため、クロスプラットフォームを考えないで良い

今後社内の状況が変わり、プロダクトに要求される内容が変われば、ネイティブで作り直したほうがいいと思う時が来るかもしれないし、来ないかもしれない。

airbnbのようにインフラストラクチャ部門が自分が感じた不満を解消してくれるなら、AndroidStudioで開発してもいい…かもしれない。

採用については、なるほどと思った。確かにRNのイメージが強すぎる場所にわざわざios/androidネイティブが強い/好きなエンジニアは応募しないだろう。

先の事はどうなるかわからないが、自分が好きで選んだ技術なので自分が責任を取れる間は使い続けたい。 RN触りはじめて2年半が過ぎたが、最近だとRNDomに興奮し、またRN自体への興味もまだ尽きない。


デモを見て、どうしても試したくなったので、PIAZZAで試してみた。

PIAZZAのRN verは0.45.1のため、raect-native-domを直接入れる事はできなかった。 そこで、新規プロジェクトを作成して必要最小限のコードとデータを持ってきてタイムラインの表示ができるまでを試してみた。

作業時間は、2–3時間ほど。

環境

とりあえず動作確認できたものだけ抜粋

プロジェクト作成

Getting Startedの通りにやればいい。特に問題無し。

移植

新規作成したプロジェクトへ既存プロジェクトから最小限のコードを持ってきて、ちょっとずつエラーを解決していくだけ。。

デバッグ

reactotronが普通に使えたので問題無し。

ライブラリ

ract-native-router-flux

v4はじめて使ったが、Scene, tab共に問題無く動作。

redux/redux-saga

こちらも問題無し。

react-native-scrollable-tab-view

  • Button.ios.jsやButton.android.jsとPlatoformでファイルが別れていたため、Button.dom.jsを作成した。(Button.ios.jsをcopy)
  • Platform.OS === ‘ios’ を Platform.OS !== ‘android’ に変えてやると動く。だが表示は崩れる。

react-native-animatable

動いた。

通信

rails4

こちらを参考にクロスドメイン対応

クライアント

superagentでうまく行かなかったのでfetchへ変更。

メモ

  • modal未対応
  • Text: numberOfLinesは未対応
  • スクリーンサイズを見て座標を調整してる箇所が一部ずれた。サイズ取得のタイミングの問題だろうか。
  • スクロール位置を見てfetchする処理が上手く動かなかった。スクロール時のイベントが上手く取れてないか。実装されてないか。(movieデモは問題無さそうだが…)
  • ScrollViewの引っ張って更新も動かない。引っ張れない。
  • Text: allowFontScaling={false} 表示が崩れる。 

感想

  • 既存プロジェクトはmovieデモのように動かすのは現時点では一筋縄ではいかない。
  • 最初、ブラウザで赤いエラー画面が出るだけでもテンションがあがる。
  • 完成度が高まれば、既存プロジェクトを簡単な修正のみでwebで動かせるようになるのではないだろうか。期待が持てる。
  • 引き続き注目していきたい。


AndroidStudio 2.3.1 → 3.1.2 へ移行した際の作業メモ。

AndroidStudioのみのupdateであれば、自分の環境では特に問題発生せず。 ただ、この機会にgradleも最新版にしてみようとしたらいくつか問題が発生した。

gradle 3.1.0以降は、Build Tools 27.0.3 以降が必要

https://developer.android.com/studio/releases/gradle-plugin#3-1-0

buildscriptのrepositoriesにgoogle()を追加しないとビルドエラー

         // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.google.gms:google-services:3.0.0'
}
}
allprojects {
...
}

リリースビルドでエラー

https://github.com/react-navigation/react-navigation/issues/3097

上記のコメントの対応でOK。


PIAZZAのandroidアプリ初期リリース(2015年10月末)直前に、軽く使い方を調べて何となく使っていたが、画像付きpush通知を実装するにあたり色々調べ直した際の作業メモ。

もし、これからfcmを使うならreact-native-firebaseのほうが良さそうだ。

環境

  • react-native-fcm@14.1.3

サーバーサイド(rails)

個別通知

AWS SNSからFCMへ通知を送っている。 設定以外で、ハマり/忘れそうなポイントは

  • publish::messageに渡すjsonは文字列で無いといけない。 → FCM用のオブジェクトを作ったらto_jsonしたものを文字列として渡す

topic通知

こちらはfcm.send_to_topicで送るだけ。 送るデータはハッシュのままで問題無い。

custom_notification

サンプルを見ると画像を送るにはpictureというkeyを設定してあげれば良い。

ただし、custom_notificationを使ってデータを送る必要がある。 https://github.com/evollu/react-native-fcm/issues/533

コメントにもあるように、通常のnotificationとcustom_notificationを同時に設定してはいけない。

作業の時に時間食ったミス。 最初以下の形式だったので、単純にnotificationをcustom_notificationに名前変えるだけだろうと思ってしまった。

こう書かないとダメ

pictureとbig_textの関係

pictureで設定した画像とbig_textで設定したテキストが表示される領域は一緒である。 両方セットした場合はpictureが優先されbig_textは表示されない。

クライアント(android)

FCMEvent.Notificationでpushされたデータを受け取ってハンドリングする際、payloadでデータを受け取れるが、custom_notificationで来たデータは、文字列になる。 よって、payloadにcustom_notificationが入っていたらparseが必要。

通常の形式

の場合はそのまま使えるので注意。サーバーから送るデータの形式は統一したほうがいい。

show_in_foregroundの代わりにローカル通知

show_in_foreground使うと、アプリがフォアグランドにある場合も通知を表示できる。 だが、全ての通知が表示されるためアプリ側で通知の表示を判定したい場合は使えない。

そこで、起動中に受け取った通知内容を条件に応じてローカル通知で表示するようにした。

ファオグラウンドの判定はAppState.currentStateを使う。


ログアウトした際に、全てのstoreをリセットする方法を探した際のメモ。

https://stackoverflow.com/questions/35622588/how-to-reset-the-state-of-a-redux-store

上記参考に、専用のaction(ROOT_CLEAR)が来たらundefinedを返すようにした。

const rootReducer = (state, action) => {
const flag: boolean = action.type === RootActions.ROOT_CLEAR;
return reducer(flag ? undefined : state, action);
};
export default rootReducer;

emacsでRustを読み書きする環境を調べた際のメモ。

emacsは GNU Emacs 25.2.1 (x86_64-apple-darwin16.5.0) of 2017–05–12

いくつか調べた結果、こちらのページに書いてあるpackageの導入と設定で上手く動いた。

だが、flycheckで以下のエラーが。

上記エラーをそのままググると以下のissueが見つかる。https://github.com/flycheck/flycheck/issues/1288

上記issueのコメントに関連するPRがありmergeされてたので、手元のflycheckをupdateしたら解決した。


react-native-device-info@0.9.5 -> 0.21.5へのupdateでビルドエラーを回避した際の作業メモ。

発生したエラー/対策

readmeのTroubleshootingに記載あり https://github.com/rebeccahughes/react-native-device-info#troubleshooting

app/build.gradleに以下を追加

その後、

してから、 react-native run-android を実行する。

OKUSAWA Takashi

programmer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store