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

React Native + Cloudflare Worker で個人開発アプリを作っている話

Kyosuke Hiraizumi
August 07, 2024
120

React Native + Cloudflare Worker で個人開発アプリを作っている話

React Native Meetup #17 の登壇資料です。

Kyosuke Hiraizumi

August 07, 2024
Tweet

Transcript

  1. 自己紹介 平泉 京祐 / @hirai_kyo / github.com:HiraiKyo 所属: CA技研 技術:

    仕事で ROS / Python / C++ 趣味・副業で Typescript / Node.js / C# 趣味: ポーカーやってます!
  2. LT趣旨 • 完成まで来たので、とりあえず自慢したかった!! • 技術的な深堀りポイントは特にない… ◦ 企画 ~ 設計 ~

    実装 の俯瞰的LTができれば • ビジネスモデルから詳細設計まで質問対応するLTは珍しい(?) • (おまけ) バックエンドにCloudflare Workerを採用した話
  3. Hashigoで解決する課題 既存テニスアプリの調査 顕在ニーズ 実力が自己申告制 Lv1 ~ 10 を自分で設定 同レベルでも結構差がある ⇒

    ELOレーティング導入 潜在ニーズ 相手を探すのが手間 場所, 日時, 参加者, レベル, etc… Tinderくらい手軽に探したい ⇒ マッチメイキング方式を採用 ELOベースのマッチメイキング方式テニス対戦アプリ
  4. Hashigo クライアント側の機能 機能要件 位置情報 expo-location 地図表示 react-native-maps ユーザプロフィールの編集 react-hook-form プロフィール画像のアップロード

    expo-image-picker プッシュ通知 expo-notifications WebSocketでマッチメイキングサーバと通信 標準ライブラリ 非機能要件 認証 Firebase JS SDK UIライブラリ React Native Paper エラーログ収集 Sentry
  5. マッチメイキングサーバ OpenMatch • ゲーム向けのOSSマッチメイクフ レームワーク • マッチメイクロジックをどこまで弄れ るか分からなかった • ドキュメントが整っていない

    自作 • コアであるマッチメイクロジックを 外部に依存したくなかった • Cloudflare DurableObjectsが 使いやすい! • クラウド上に存在するシングルトン クラス • WebSocket Hibernationでコス トダウンも可能
  6. サーバサイド : Cloudflare DurableObjects の実装例 export class MatchmakingDurableObject extends DurableObject

    { private _queues: QueueType[] = []; constructor(readonly state: DurableObjectState, readonly env: Env) { super(state, env); this.state.blockConcurrencyWhile(async () => { let stored = await this.state.storage.get<string>('queue'); this._queues = stored ? JSON.parse(stored) : []; }); } async addQueue(participant: Participant): Promise<void> { const q: QueueType = { queueId: uuidv4(), participant, createdAt: new Date(), }; this._queues.push(q); await this.state.storage.put('queue', JSON.stringify(this._queues)); } } • “マルチユーザーのシングルトンク ラス”のように書ける • サーバーレスでありながら、一意 のクラスインスタンスのように振る 舞う • DBやKVStoreではなく In-memory stateにデータ保持 • 衝突はCloudflare側でキュー管 理してくれる
  7. 認証 • Firebase JS SDKを利用 ◦ Authentication, Firestore, Realtime Database,

    Storageのみ 利用可能 ◦ react-native-firebase の利用も検討したが、prebuildで苦労した ◦ Firebase Crashlyticsを使わずにSentryを使うことにした • Cloudflare Access を導入してみたい
  8. 地図表示 • react-native-maps を利用 ◦ GoogleMapsAPIの設定が必要 ◦ Web対応していないので、パッチ処理を行う ▪ https://stackoverflow.com/questions/76629674/unable-to-resolve-utilities-platform-error-with-metro-bundler

    • Expo SDK 51ではGoogle MapsがiOSでサポートされず、Apple  Mapsに置換された ◦ provider={PROVIDER_GOOGLE} を削除する ◦ https://github.com/expo/expo/issues/28705
  9. ユーザプロフィールの編集 • react-hook-form を利用 ◦ register を使って書けない(?) control を使う export

    default function App() { const { control, handleSubmit, formState: { errors }, } = useForm({ defaultValue : { firstName: "", }, }) const onSubmit = (data) => console.log(data) return ( <View> <Controller control ={control} rules ={{ required: true, }} render ={({ field: { onChange, onBlur, value } }) => ( <TextInput placeholder ="First name" onBlur ={onBlur} onChangeText ={onChange} value ={value} /> )} name ="firstName" /> {errors.firstName && <Text>This is required. </Text>} </View> ) }
  10. 画像のアップロード • expo-image-picker を利用 ◦ blobだと送信できず、 右記のような形で送信する らしい ◦ 詳細は、

    https://www.simpletraveler.jp/2021/09/30/%E3%80%90reactnative%E9%96%8B%E7% 99%BA%E3%80%91formdata%E3%81%A8%E3%81%9D%E3%82%8C%E3%81%AB%E9%9 6%A2%E3%82%8F%E3%82%8B%E6%8A%80%E8%A1%93fetchxhrmultipart-form-data- %E3%82%92%E7%90%86%E8%A7%A3/ const permissionResult = await ImagePicker .requestMediaLibraryPermissionsAsync (); const result = await ImagePicker .launchImageLibraryAsync ({ mediaTypes: ImagePicker .MediaTypeOptions .Images, allowsEditing: true, aspect: [1, 1], quality: 1, }); const uri = result.assets[0].uri; const mimeType = result.assets[0].mimeType; const fileExt = uri.split(".")[uri.split(".").length - 1]; const formData = new FormData(); formData.append("file", { uri, name: `image.${fileExt}`, type: mimeType, }); const res = await fetch(uploadUri, { method: "POST", body: formData, });
  11. プッシュ通知 • expo-notifications を利用 • expo-server-sdk-node でバックエンド実装 ◦ Cloudflare Worker

    の Node.js Compatible モードがうまく機能 せず、Node.js API でエラー ▪ assert は自分で書いた ▪ zlib は pako に置換
  12. UIライブラリ選定 Expo SDK 51 で使えるもの • React Native Paper •

    Tamagui 使えなかったもの • RNUILib • React Native Base ⇒ ビルドまで含めてテストすべき