Expoで始めるiOS/Android/Web対応Universal App開発!
こんにちは!テラーノベルでiOS/Android/Webとフロントエンド周りを担当している @kazutoyoです!
この頃React Native、Expo熱が高まっております🔥
最近ではDiscordのAndroid版もReact Native化されたり、ツイッターの後継として注目されているBlueskyのiOS/AndroidとWebがExpoで作られていたりと、React Nativeの波がまた来ているのを感じています。
今回はそんなReact NativeをExpoというフレームワークを利用し、Web/ネイティブで動作するInstagramのようなアプリケーションを作ってみます。
先に完成品を載せますが、このような Web / iOS / Android で動作するアプリケーション(Universal App)を構築できます🥰
Expoとは
ExpoはReact Nativeをベースにしたフレームワークで、iOS/AndroidのネイティブアプリとWebをサポートしています。
また、Expo Application Services(EAS)と呼ばれるクラウドサービスを利用することで、アプリケーションのビルドやストアへの配布を行うサービスも提供されています。
素のReact Nativeで扱いにくい部分をExpoはいい感じに隠蔽してくれることで快適な開発体験を提供してくれます!
React Nativeってどう?
個人的にはとても気に入っています。
現在テラーノベルではWebViewで作られている一部機能をリニューアルするプロジェクトを進めています。
その部分をマルチプラットフォームで対応できるフレームワークとしてReact NativeとFlutterで検討していました。
Flutterも非常に勢いがあり、コミュニティも活発であると感じていましたが、以下のようなこともあって私たちはReact Nativeを採用することにしました。
- 元々WebViewで表示していた部分はReact.jsで作られているので、React Nativeに移植がしやすい
- チームとしてのReactの経験者が多い
- Web版も提供予定
- React Native for WebとFlutter on the Webを比較したとき、RNはReact.jsのように変換されるためハマりどころが少なそう
- React Nativeの場合Next.jsと組み合わせてSSRも可能
- Flutter on the WebはPWAやSPAのようなつくりのアプリケーションへ焦点を当てている https://docs.flutter.dev/platform-integration/web/faq
- React Native for WebとFlutter on the Webを比較したとき、RNはReact.jsのように変換されるためハマりどころが少なそう
- Dart/FlutterとTypeScript/ReactだとTypeScript/Reactのほうが好み
- フロントエンドチームで扱う言語がSwift/Kotlin/TypeScriptがあり、さらにDartも追加することでスイッチングコストが更に高くなる
ExpoでUniversal Appを作ってみよう!
セットアップ
今回はこれらのライブラリを使いながら、Instagramのようなアプリケーションを作ってみます。
- Expo
-
Expo Router
- Next.jsのようなファイルシステムでのルーティングライブラリ
-
Tamagui
- デザインシステム、スタイリング、UIコンポーネントライブラリ
-
React Native Reanimated
- React Nativeのアニメーションライブラリ。今回はシーン間のShared Element Transitionに利用しています。
-
Next.js
- Webで実行時に利用
- 今回は利用していませんが、場合によってはSSRも可能
- Webで実行時に利用
-
Solito
- React NativeのnavigationとNext.jsのnavigationを抽象化して扱うためのライブラリ
まずはcreate-tamaguiを使い、 next-expo-solito
プロジェクト構成でアプリケーションを作成します。
以下のコマンドを実行し、Project name、Git管理するか、 Pick a template
は Next + Expo + Solito
を選択します。
npm create tamagui@latest
セットアップ完了後、プロジェクトに移動し yarn web
や yarn native
を実行してみましょう!
yarn web
ではWebが起動、 yarn native
ではReact Nativeでのネイティブアプリケーションが実行されます。
実際に動かしてみたところこんな感じです。WebとNativeで若干動きが異なりますが綺麗に動いていますね!
プロジェクト構成
create-tamaguiで作成されたプロジェクト構成はこのようなmonorepoの構成となっています。
-
apps/
-
expo
: Expo(React Native)でのアプリケーション。Expo Routerにより、packages/app
の画面を配置している。 -
next
: Next.jsのアプリケーション。expoパッケージと同様に、Next.jsのルーティングでpackages/app
の画面を配置している。
-
-
packages/
-
app
:-
features
:apps
で利用される機能ごとの画面が実装されている -
provider
:apps
で利用される、Providerなどが実装されている
-
-
ui
: TamaguiによるUIコンポーネントやカスタムコンポーネント、app
で利用されるコンポーネントや、デザインシステムの定義などUIに関する実装
-
また、これら以外にも必要があれば packages
にmonorepoとして追加して利用することができます。
詳細につきましてはこちらをご参照ください。
コンポーネントの作成
次のようにtamaguiを使いコンポーネントを作成していきます。
Reactのchakra-uiなどを利用されたことがある方でしたら、そこまで違和感がなくスタイリングが出来るかと思います。
Screenの作成
作成したコンポーネントを使い、スクリーンを作成します。
Expo / Next.jsに配置
コンポーネント、スクリーンを作成したあとは、 apps
配下の expo
と next
のルーティングに作成したスクリーンを配置します。
Expo
例として /app/user/[userId]
のページでは次のようにします。
Stack.Screen
を使い、スクリーンのタイトルをセットします。
Next.js
Next.jsも同様に行います。
/pages/user/[userId]/index.ts
では next/head
でタイトルをセットします。
完成品 🎉
このようにWeb/ネイティブで動くアプリケーションができました!
こちらのソースコードはこちら
まとめ
このように非常に簡単にUniversal Appを構築することが出来ました。
TamaguiでのレイアウトでネイティブとWebで若干挙動が異なることもあり、その点だけ微調整が必要ではありましたが、基本的に1度書けばネイティブアプリとWebの両方が対応できて素晴らしかったです。
先日行われました App.js conf 2023でExpo SDKやExpo Routerの新バージョンが発表されており、今後よりUniversal Appの開発体験や機能が向上していくと予想されます。
FlutterやJetpack Composeなど、React Nativeの競合として様々なマルチプラットフォームのUIフレームワークが登場していますが、それぞれが相互にフィードバックを与えながらより良い進化をしていくと良いなと考えています。
Discussion