子供向けにチャットアプリを作ってみた

## はじめに
ここ数年間React Nativeを触れる機会がなかったのですが、キャッチアップのために子供が使えそうなチャットのアプリを作ってみました。普段からWebのフロントエンドもReactで実装することがほとんどなのでやはり大きく迷うことはなく、Expo（特にEASのよるビルド、デプロイ）とFirebase、React Native Paperでかなりスムーズに進んだ印象です。本記事では使用した開発スタックと少し実装面の説明、出来上がったアプリの紹介などをしたいと思います。

## 開発Stack

ざっとこのような感じです。

- [Expo](https://expo.dev/)（EAS、Expo Routerが便利）
- [Firebase](https://firebase.google.com/)（Authentication、Firestore）
- [React Native Paper](https://reactnativepaper.com/)（Material Designのコンポーネントライブラリ）
- [RevenueCat](https://www.revenuecat.com/)（課金機能）
- [AppSync](https://aws.amazon.com/jp/appsync/)（GraphQLでマイクロサービスへのリクエスト）
- [Terraform](https://www.terraform.io/)（インフラ）

[react-hook-form](https://react-hook-form.com/)や[zustand](https://github.com/pmndrs/zustand)など、ロジック部分ではほとんど普段Webで使っているライブラリを使用していて、Webでも同様のサービスを展開する際はほとんど再利用できそうな印象でした（逆にWebからReact Nativeに展開する場合も）。

### Expo
少し最初の導入ステップの辺りも触れておきます（執筆時に使っていたExpoのバージョンは `v50.0.8`）。

XCode、Android Studio、Node.js、Watchman等、React Nativeに必要な一通りのツールのインストールと設定が終わったら、開発用のディレクトリで以下を実行します。

```bash
npx create-expo-app --template
```

`Typescript` をtemplateで選び、app nameを設定、その後ライブラリのインストールが開始されます。インストール後 `npm start` するとコマンドのオプション一覧が出るので `i` でiOSシミュレータを選択して起動（もしくは `a` でandroid）。サンプルのページが表示されれば開発準備OKです。

同梱されている `Expo Router` はNext.jsなどでも採用されている `file-based router` で、ディレクトリごとに `_layout.tsx` を配置することで、そのディレクトリ内のページのレイアウトやProviderの設定などが行えます。

今回はログイン前とログイン後に大きくディレクトリを分け、その中でさらにいくつかディレクトリ分けをしました。

https://docs.expo.dev/router/introduction/

### Firebase

初期の開発時にExpoのEASやprebuildに関して何も知らず、[react-native-firebase](https://rnfirebase.io/)を使うとExpoをejectしないといけないと勝手に思っていました。そのためWebで使うものと同じFirebaseのライブラリを使っていました。今後タイミングを見てreact-native-firebaseに移行しようと思っています。

後述する[RevenueCat](https://www.revenuecat.com/)もそうですが、ネイティブコードに依存するライブラリを使用する際は`npx expo prebuild`(`ios`と`android`ディレクトリが作られる)した後に、`npx expo run:ios`（もしくは`npx expo run:android`）すればシミュレータで動作確認しながら問題なく開発を進められます。実機で確認しながら進める場合は[expo-dev-client](https://docs.expo.dev/versions/latest/sdk/dev-client/)が便利です。


https://rnfirebase.io/

### React Native Paper

Paperが便利でした。このように`PaperProvider`で包んで、あとは必要な箇所でコンポーネントをimportするだけ。GraphQLクライアントには今回react-queryを使っています。

```tsx
...
// react-query client
const queryClient = new QueryClient();

return (
  <RevenueCatProvider>
    <QueryClientProvider client={queryClient}>
      <PaperProvider theme={theme}>
        ...
      </PaperProvider>
    </QueryClientProvider>
  </RevenueCatProvider>
);
```

`babel.config.js` の設定だけ少し調べた気がします。

```js
// babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    env: {
      production: {
        plugins: ["react-native-paper/babel"],
      },
    },
    plugins: [...],
  };
};
```

https://reactnativepaper.com/

### RevenueCat

`Products`、`Packages`、`Entitlements`、`Offerings`など課金まわりの概念をまず理解する必要があるのですが、一旦そこを理解してしまえば課金のライブラリ[react-native-purchases](https://github.com/RevenueCat/react-native-purchases)を組み込む際も割とスムーズに進められた気がします。実装時はできるだけ課金のステータスのログを確認しながら進め、Appleのサンドボックスアカウントを使うことで確認時に課金が発生せずに済みました。月の売上が2500ドルを超えると売り上げの1%を手数料が発生するとのことです。

https://www.revenuecat.com/

### 開発に費やした時間
早く終わらせたかったので後半実装が雑になりましたが（そのうちにリファクタリング予定）、すきま時間を使って3ヶ月ほどでできたかと思います。

## Appleのレビューで却下される

元々Kids Chat的な名前で子供向けにアプリを提出したのですが、Appleに却下されました。キッズカテゴリーでチャット機能の使用は許可されていないとのことで、結局対象年齢は指定せず、「大人から子供まで誰でも簡単に使えるチャットアプリ」としました。名前は「DuoChat」。一対一という意味で `Duo` という表現を使いました。できるだけグループチャットやソーシャルな要素は排除して、知っている人と連絡を取ることをメインにしています。

## 機能の紹介

最後に、少し機能の紹介をしておきます。一般的なチャット機能に加え、以下のような機能を持たせました。

### 文字サイズ機能
文字サイズを3段階まで変更できます。

![textsize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674308/04a4ed37-d1ce-3c35-5e5c-136856f720b7.png)

### 送信内容のチェック
送信前のチェック。子供が誤って個人情報を送信してしまうなどを防止します。

![validation.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674308/7d29bcf1-8840-62c9-281f-b1ee617c8903.jpeg)

## App Store
ほとんどの機能は無料で使えます（友達の上限が8名なのと、通知機能がないですが）

https://apps.apple.com/jp/app/duochat/id6478688785

## まとめ

リリースまで一通り進めたことでReact Nativeまわりのライブラリやツール、開発フローに関してのキャッチアップがある程度できたかと思います。同様のReactベースのWebサービスも展開するのであればView以外のロジック部分のJS/TSはほとんど再利用ができるのでかなり生産性が高まる気がしました。作ったアプリに関してはニーズを見て今後機能拡充を進めていきます。