Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React Native×Firebaseで オンライン指導用の チャットアプリを開発している話

7fccfb690a818ed2f3a15fc21d426d5a?s=47 meijin
March 04, 2021

React Native×Firebaseで オンライン指導用の チャットアプリを開発している話

7fccfb690a818ed2f3a15fc21d426d5a?s=128

meijin

March 04, 2021
Tweet

Transcript

  1. React Native×Firebase で オンライン指導⽤の チャットアプリを開発している話

  2. ⽬次 ⾃⼰紹介 開発しているサービス React Native の利⽤ライブラリ React Native の品質管理 React

    Native の落とし⽳ Firebase の利⽤ライブラリ Firebase の品質管理 Firebase の落とし⽳ この技術選定で良かったと思うこと まとめ
  3. ⾃⼰紹介 ハンドルネーム” 名⼈” 株式会社NoSchool CTO オンライン家庭教師を広める教育サービス” マナ リンク” を開発しています(https://manalink.jp) 好きな⾔語はTypeScript

    好きなIDE はPHPStorm 趣味 将棋( 指すのも観戦するのも好き) ゲーム( 最近はゼルダ無双)
  4. 開発しているサービス マナリンク 中⾼⽣向けのオンライン家庭教師サービス Web 上で先⽣を探して指導依頼 指導開始後はアプリを使ってご家庭↔ 先⽣でやり 取り

  5. 図にするとこんな感じ

  6. 図にするとこんな感じ

  7. アプリの開発体制と利⽤技術 開発体制 業務委託エンジニア1 名(+ ときどき CTO) めっちゃベンチャーです 利⽤技術 React Native

    Expo(Managed Workflow) Firebase TypeScript
  8. React Native の利⽤ライブラリ

  9. react-native-gifted-chat < <GiftedChat GiftedChat messages messages= ={ {chatMessages chatMessages} }

    onSend onSend= ={ {onSend onSend} } placeholder placeholder= =" メッセージを⼊⼒" " メッセージを⼊⼒" renderBubble renderBubble= ={ {renderBubble renderBubble} } renderInputToolbar renderInputToolbar= ={ {renderInputToo renderInputToo renderActions renderActions= ={ {renderActions renderActions} } renderComposer renderComposer= ={ {renderComposer renderComposer} } renderSend renderSend= ={ {renderSend renderSend} } renderMessageImage renderMessageImage= ={ {renderMessageI renderMessageI infiniteScroll infiniteScroll // 以下略 // 以下略 / /> > チャット画⾯を丸っと囲う GiftedChat コンポーネントを置くだ け 各メッセージや送信ボタンなどは外 からFunctional なComponent を渡す ことでカスタマイズできる カスタマイズしすぎるとライブラリ の範囲を逸脱してくるので、いつか はリプレイスする
  10. チャットをゼロから作るのは割と⼤変 以下の内容は react-native-gifted-chat が やっている チャットの吹き出しの形 よく⾒ると、連投したときの⾓丸の形が微妙に 違う 連投すると最後の投稿だけユーザーアイコンが つく

    ⽇時表⽰ ⽇付が変わるたびに⽇付表⽰をインサートして いる 表⽰位置 新着メッセージが来るたびに⾃動でスクロール Web ではVue で全部⾃作したけど結構⼤変だった( 勉
  11. Firebase×React Hooks 関連のライブラリ react-firebase-hooks https://github.com/CSFrequency/react-firebase-hooks Firestore のCollection データ、読み込み中フラグ、エラー内容をセットで返すHook const const

    [ [values values, , loading loading, , error error] ] = = useCollectionData useCollectionData< <T T> >( (query query, , options options) ); ; react-firebase-pagination-hooks チャットのメッセージをページングして、無限スクロールを実装 loadMore メソッドを実⾏すれば次のデータが読み込める const const [ [messages messages, , { { loaded loaded, , loadingMore loadingMore, , loadMore loadMore } }, , error error] ] = = usePaginationData usePaginationData< <T T> >
  12. React Native の品質管理 React Native に関してはテストコードは皆無( 汗) 機能が少なく、ライブラリ依存が⼤きいため 毎回ウォークスルーテストを⼿動でしている エラー検知はSentry

    画⾯遷移やメッセージ送信時などでイベントを発⽕して記録 エラーログが出ると、イベントを辿ることでユーザーの動きを擬似再現できる ユーザーID も紐付けができる ソースマップをSentry にデプロイすることで、エラーが起きたソースコードの該 当箇所を特定しやすい Sentry Sentry. .addBreadcrumb addBreadcrumb( ({ { category category: : 'ACTION' 'ACTION', , message message: : 'SEND_CHAT_MESSAGE' 'SEND_CHAT_MESSAGE', , data data: : { { roomId roomId: : room room. .id id, ,
  13. React Native の落とし⽳ ハマると解決が厳しい 某ライブラリと某ライブラリを併⽤し、かつ特定の動作をユーザーが⾏うとアプリ がクラッシュする事案があった 画⾯が突然ブラックアウトして強制的に再起動になる クラッシュが突然ブラックアウトするためエラーログが取れない ライブラリのソースを追っても、ある程度追うとネイティブのコードになり謎が 深まる

    結局何が原因か分からないままに、当該ライブラリの組み合わせを変えることで解消...
  14. いつでもiOS/Android で同じと思うなよ現象 チャットで画像を送信するとき、画素数を落とさずにファイルサイズを⼩さくする ために圧縮した expo-image-manipulator のImageManipulator.manipulateAsync で圧縮しようと すると、同じ圧縮率を指定してもAndroid から実⾏すると画像が圧縮されすぎて しまった

    OS ごとに分岐して圧縮率を調整することで解消 ソースレビューの段階では何ら問題なく⾒えるので恐ろしい 他にも通知周りなど、細かいところで結局OS ごとに分岐する箇所があるので、両 OS での実機確認は必須
  15. Firebase の利⽤ライブラリ Cloud Functions 側で使っている技術を軽く紹介していきます

  16. firestore-simple Firestore に対する形安全なDAO が⼿に⼊れられるライブラリ const const roomDao roomDao = =

    firestoreSimple firestoreSimple. .collection collection< <Room Room> >( ({ { path path: : 'rooms' 'rooms' } }) ) const const allRooms allRooms = = await await roomDao roomDao. .fetchAll fetchAll( () ) // allRooms: Room[] // allRooms: Room[]
  17. Firebase の設計 Firestore は書き込み処理に重点を置く SQL と違って読み取りクエリが貧弱 ⾮正規化を許容して、読み取りの仕様に合わせて最適化したコレクションを作る 例:チャット部屋⼀覧で最新のメッセージを⾒せるために、messages コレクション のonCreate

    でrooms コレクションに最新のメッセージを遅れて同期させる 例:全ての未読数の合計を出すために、messages へのonWrite ハンドラでユーザー ごとに未読数を集計して別途保存する
  18. Firebase の品質管理 Functions でのエラーログをSlack 通知 https://zenn.dev/meijin/scraps/94d4a70eb77507 Functions でキャッチされなかった例外も含めSlack 等でキャッチアップしたかった Cloud

    Functions ログ→GCP→ ログルーター→PubSub トピック→Cloud Function→Slack 通知
  19. Firebase の落とし⽳ Firebase というかExpo の落とし⽳だが、Expo へのPush 通知は割と⾼頻度( 週に数 回) で502

    エラーになる 400 系なら分かるが、502 ならどうしようもない Expo に問い合わせたが、リトライ処理を実装してくださいとのことだったので、 ⾃前で実装しました
  20. React Native で良かったと思うこと

  21. 1. 簡単な修正ならWeb エンジニア( 僕) でも理解・実装できる そもそもReact が個⼈的に好き( 突然の主観) 最近練習を兼ねてRN で個⼈開発しているが、TSX

    を書くのが楽しいしスタイルも CSS 感覚なので敷居が本当に低い Expo のおかげで環境構築時やコードを書くときに各OS の存在をほとんど意識しな くて良い Firebase JS SDK のコードをNuxt.js とRN でほぼコピペ可能 先⽇Firebase のStorage にファイルを上げる時に、content-disposition ヘッダを指 定することでダウンロード時にファイル名を維持する施策を実装したが、ほぼ同 じコードでWeb/ アプリを実装できたので便利さを実感した
  22. 2. 受験シーズンに間に合うように開発できた! 昨年6 ⽉から開発スタートし10 ⽉にリリース React Native で開発することで受験シーズンに間に合い、積極的に使ってもらう ことができた ほぼチャット機能のみのシンプルなアプリでも好評だった

    親・先⽣・⽣徒がやり取りでき、ファイルや画像も送れるのは当然に⾒えて、案 外事業者側でそこまで内製する企業が少ないらしい 宿題や過去問などファイルをやり取りすることは想像以上に多く、特に先⽣から 好評をいただくことができた 教育事業が最も盛り上がる受験シーズンまでに、最低限どんな機能があればニーズ が満たせるか理解できた スタートアップの検証サイクル的にはとても有り難い技術 ( 初期リリースの内容を予定から絞って、チャットだけを作り込む判断も功を奏し た)
  23. まとめ React Native のチャット機能開発 UI はreact-native-gifted-chat が便利 データ読み込みはHooks 関連のライブラリが便利 エラー検知はSentry

    が便利 Firebase のチャット機能開発 読み取りの都合に合わせて⾮正規化や冗⻑性を許容する Cloud Functions のonWrite 等を使って同期 開発体制を柔軟に決められる技術スタックなので⼤変助かっている
  24. 告知

  25. ご清聴ありがとうございました Twitter: @Meijin_garden