🈳

React Nativeでアプリを作るときは、bluesky-social/social-appを参考にしよう!

に公開

こんにちは!テラーノベルとテラードラマでiOS/Android/Webとフロントエンド周りを担当している @kazutoyoです!

タイトルの通りなのですが、これからReact Nativeでアプリを作ろう!という人はblueskyの公式クライアントアプリを参考にしましょう!
https://github.com/bluesky-social/social-app

なぜbluesky-social/social-appを参考にするのか

多くのユーザーがいるサービスで、継続的に開発されている

実際に多くのユーザーがWebやアプリで利用しているサービスであり、それがOSSで公開されているのは凄いですよね。
ストアやWebで公開されているアプリケーションなので、実際にアプリをインストールして触りながら、この部分のコードはどうなっているんだろう?と確認することもできるのもキャッチアップしやすい点かと思います。

技術スタックがモダンな作りになっている

Expoを利用しており、Webに関してもReact Native for Webを利用するような作りになっています。
Expo Modulesの利用や、ExpoのCNGにも対応していたりと、Expoの機能をフルに使って開発されています。

また、Tanstack QueryやZod、ZeegoなどのUIライブラリなど、人気の高いライブラリが利用されています。

より詳細な技術スタックはこちら

📱 コアフレームワーク

  • React Native - クロスプラットフォームモバイルアプリ開発
  • Expo - React Native開発プラットフォーム
  • React - UIライブラリ
  • React Compiler Runtime - React最適化
  • React DOM - Web版レンダリング
  • React Native Web - React NativeコンポーネントのWeb対応
  • React Native Web Webview - WebView対応

🧭 ナビゲーション

  • @react-navigation/native - ナビゲーションの基盤
  • @react-navigation/native-stack - スタックナビゲーション
  • @react-navigation/bottom-tabs - タブナビゲーション
  • @react-navigation/drawer - ドロワーナビゲーション
  • React Native Screens - ネイティブ画面最適化
  • React Native Pager View - ページビュー

🎨 UI/UXコンポーネント

アニメーション・インタラクション

  • React Native Reanimated - 高性能アニメーション
  • React Native Gesture Handler - ジェスチャー処理
  • Expo Haptics - 触覚フィードバック

UI要素

  • @discord/bottom-sheet - ボトムシート
  • @react-native-menu/menu - コンテキストメニュー
  • @miblanchard/react-native-slider - スライダー
  • React Native iOS Context Menu - iOS用コンテキストメニュー
  • React Native Keyboard Controller - キーボード制御
  • React Native Date Picker - 日付選択
  • React Native Progress - プログレスバー
  • Zeego - ネイティブメニュー

画像・メディア

  • Expo Image - 高性能画像コンポーネント
  • Expo Image Picker - 画像選択
  • Expo Image Manipulator - 画像編集
  • Expo Image Crop Tool - 画像クロップ
  • Expo Camera - カメラ機能
  • Expo Media Library - メディアライブラリアクセス
  • React Native View Shot - スクリーンショット
  • React Native Compressor - メディア圧縮
  • React Image Crop - Web用画像クロップ

ビデオ

  • @haileyok/bluesky-video - ビデオ処理
  • Expo Video - ビデオ再生
  • hls.js - HLSストリーミング

グラフィックス

  • React Native SVG - SVGサポート
  • Expo Linear Gradient - グラデーション
  • Expo Blur - ブラー効果
  • React Native QRCode Styled - QRコード生成

📝 テキスト編集

  • @tiptap/core - リッチテキストエディタコア
  • @tiptap/react - React統合
  • @tiptap/extension-mention - メンション機能
  • @tiptap/extension-placeholder - プレースホルダー
  • @tiptap/extension-history - 操作履歴
  • React Native UITextView - ネイティブテキストビュー
  • @mattermost/react-native-paste-input - ペースト入力
  • React Textarea Autosize - 自動リサイズテキストエリア

🗄️ 状態管理・データ

データフェッチング

  • @tanstack/react-query - データフェッチング・キャッシング
  • @tanstack/react-query-persist-client - 永続化
  • @tanstack/query-async-storage-persister - AsyncStorage永続化

ストレージ

  • React Native MMKV - 高速キーバリューストレージ
  • @react-native-async-storage/async-storage - 非同期ストレージ
  • Expo File System - ファイルシステムアクセス

API・通信

  • @atproto/api - AT Protocol API
  • @atproto/dev-env - 開発環境
  • React Native Webview - WebView

🌍 国際化・ローカライゼーション

  • @lingui/react - React用i18n
  • @lingui/macro - マクロ変換
  • @lingui/cli - CLI ツール
  • Expo Localization - デバイスロケール取得
  • @formatjs/intl-locale - ロケール処理
  • @formatjs/intl-numberformat - 数値フォーマット
  • @formatjs/intl-pluralrules - 複数形ルール

📊 モニタリング・分析

  • @sentry/react-native - エラートラッキング
  • @sentry/webpack-plugin - Webpack統合
  • Statsig React Native Expo - 機能フラグ・A/Bテスト
  • @bitdrift/react-native - ログ収集

🛠️ 開発ツール

ビルド・バンドル

  • TypeScript - 型付きJavaScript
  • Babel - JavaScriptトランスパイラ
  • Metro - React Nativeバンドラー
  • Webpack - Web版バンドラー
  • @expo/webpack-config - Expo Webpack設定

コード品質

  • ESLint - JavaScriptリンター
  • Prettier - コードフォーマッター
  • Husky - Git hooks
  • lint-staged - ステージファイルのリント

テスト

  • Jest - テストフレームワーク
  • Jest Expo - Expo用Jest設定
  • @testing-library/react-native - React Nativeテストユーティリティ
  • @testing-library/jest-native - Jest用マッチャー

🔧 ユーティリティライブラリ

日付・時間

  • date-fns - 日付処理ライブラリ

バリデーション

  • Zod - スキーマバリデーション
  • email-validator - メールバリデーション

データ処理

  • lodash.throttle - スロットリング
  • lodash.debounce - デバウンス
  • lodash.chunk - 配列分割
  • lodash.shuffle - シャッフル
  • lodash.isequal - 深い比較

暗号化・エンコーディング

  • js-sha256 - SHA-256ハッシュ
  • jwt-decode - JWT デコード
  • base64-js - Base64エンコード/デコード
  • multiformats - マルチフォーマット

その他

  • nanoid - ID生成
  • uuid - UUID生成
  • normalize-url - URL正規化
  • emoji-regex - 絵文字正規表現
  • emoji-mart - 絵文字ピッカー
  • eventemitter3 - イベントエミッター

🔐 セキュリティ・認証

  • React Native Device Attest - デバイス認証
  • @braintree/sanitize-url - URL サニタイズ

📱 ネイティブ機能

システム連携

  • Expo Application - アプリ情報
  • Expo Device - デバイス情報
  • Expo Updates - OTAアップデート
  • Expo Notifications - プッシュ通知
  • Expo Task Manager - バックグラウンドタスク
  • Expo Intent Launcher - インテント起動
  • Expo Screen Orientation - 画面向き制御

共有・連携

  • Expo Clipboard - クリップボード
  • Expo Sharing - コンテンツ共有
  • Expo Linking - ディープリンク
  • Expo Web Browser - ブラウザ起動

UI/UX

  • Expo Splash Screen - スプラッシュスクリーン
  • Expo System UI - システムUI制御
  • React Native Safe Area Context - セーフエリア
  • React Native Edge to Edge - エッジツーエッジ表示
  • @mozzius/expo-dynamic-app-icon - 動的アプリアイコン

📦 開発環境

  • Expo Dev Client - カスタム開発クライアント
  • Expo Build Properties - ビルド設定
  • patch-package - パッケージパッチ
  • React Native Dotenv - 環境変数

🧪 E2Eテスト・パフォーマンス

  • Maestro - E2Eテストツール(package.jsonのスクリプトで使用)
  • Flashlight - パフォーマンステスト(package.jsonのスクリプトで使用)

Expo ModulesやConfig Pluginの対応、パッチなどが参考になる

少し発展的な内容になりますが、ExpoでNativeのAPIを呼び出したり、iOS/Androidのプロジェクトに対して変更を加える際にはExpo ModulesやConfig Pluginを作成する必要があります。
https://zenn.dev/tellernovel_inc/articles/151fbb8fe6cdbe

BlueskyのアプリでもこちらのようにいくつものExpo ModulesやConfig Pluginが書かれており、どのように作成するかの見本となります。
https://github.com/bluesky-social/social-app/tree/main/modules
https://github.com/bluesky-social/social-app/tree/main/plugins

また、一部のライブラリに対して、不具合などによりパッチを当てたいときがあります。
そういったものも、リポジトリ内のこちらのように、パッチファイルとそれを当てる理由のMarkdownファイルがセットになって設置されています。
https://github.com/bluesky-social/social-app/tree/main/patches

こういった運用上必要なものもあるんだなーというのも知ることができました。

その他参考になったこと

Application Layout Framework (ALF)

こちらのように、React NativeでのスタイリングをALFと読んでいるレイアウトの定数を定義して利用しているようです。
https://github.com/bluesky-social/social-app/tree/main/src/alf

次のような感じで、スタイルのUtilityを提供しています。

import { atoms, useTheme } from '#/alf'

const t = useTheme()

<View style={[atoms.flex_row, t.atoms.bg]} />

シンプルな感じですが、TailwindのようにUtility Firstな感じをReact NativeのStylesheet APIを使って実現しています。

多言語対応

React Nativeで多言語対応のアプリケーションを作ったことがなかったので知りませんでしたが、BlueskyではLinguiを使っているようでした。
Lingui自体はReact Nativeようではなく、WebのReactでも利用できるもののようなので、Webに対応するためにこちらを利用したのかもしれませんね。

またCrowdinという翻訳の管理ツールも利用しているようでした。

https://github.com/bluesky-social/social-app/blob/main/docs/localization.md

Native感を出す

こちらのBlueskyを開発している方のブログで、React Nativeアプリでより "ネイティブ感" を出すための方法が紹介されています。
https://whtwnd.com/samuel.bsky.team/3l777nhz4h32w

  • 境界線は 1px のような指定ではなく StyleSheet.hairlineWidth を使う
  • React Navigationの presentation="pageSheet" を指定してNativeのシートを使う
  • BottomSheetを置き換え
  • レイアウトアニメーションや、タップしたときのフィードバックなど

まとめ

このように、様々な学びがあるリポジトリでした。

React Nativeを使った開発で困ったことがあれば、まずはbluesky-social/social-appリポジトリを見て、参考にできないかチェックするのが良いかもしれませんね。

それでは良いReact Nativeライフを!

テラーノベル テックブログ

Discussion