注意 – コンテンツは記事投稿時に最新だった情報に基づいて作成しています。React Nativeは移り変わりが激しいため、変更になった情報もある可能性があることにご留意ください。
React Nativeはクロスプラットフォームのネイティブアプリケーションを構築するのに素晴らしいツールです。一つのコードベースでiOS、Android、またその他のオペレーティングシステム(MacOS, Windows, Web等、その他)のアプリを作ることはiOSのためにSwiftやObjective-C、AndroidのためにKotlinやJavaを用いて別々のコードベースを書くのと比較し、コストの削減や、いち早くマーケットに出すことを可能にし、保守性の向上も見込むことができます。
TacchiはAppleのApp StoreやGoogleのPlay Storeの初期の頃からアプリ制作を続けておりますが、当時はクロスプラットフォームツールはハイクオリティのアプリを構築する際に課題がありました。そのため、私とチームは最初の7年半ほどの間、Objective-C、Swift、Javaの各コードベースを用いてクライアントのためにアプリを作成してきました。しかし、ここ数年でReact Nativeのみを使用するようになりました。これにより前述した利点をクライアントにもたらすことができました。
しかし、React Nativeでの開発にも課題があります。特に従来の方法でネイティブモバイルアプリを作成してきたバックグラウンドがない人には起こりがちであると思います。React Nativeでの最初の課題の一つとしてはアプリのナビゲーションを構築することです。React Nativeのコアライブラリは画面間のナビゲーションのいかなるAPIを含まないためです。また、複数のオープンソースの選択肢があります。
特に、スクリーン間のナビゲーションの流れが両方のプラットフォームのユーザーにとってネイティブな挙動を保つこと、パフォーマンスが良いこと、開発がしやすいこと、保守性が高いことを確実にすることは重要なポイントです。
この記事ではネイティブUIフレームワークがどのように作られているかという初歩的な説明を行い、React Nativeプロジェクトでのナビゲーションへのアプローチの仕方に対するアドバイスを紹介する前に、React Nativeでナビゲーションを扱う際の主な選択肢を紹介し、それぞれのメリットとデメリットを提示します。
例では、モバイルアプリでスクリーンを構成し、提示する3つの定番のナビゲーション構造 “スタック、タブバー、モーダル”に焦点を当てます。
ネイティブUIフレームワーク入門
フレームワークについての簡単な紹介です。クロスプラットフォームモバイルアプリを構築する場合、使用技術に関係なくiOSヒューマンインターフェースガイドライン、GoogleのAndroidデザインを精読することが必須です。iOS、Android両方のユーザーにとって使いやすくネイティブ感覚のあるアプリをデザイン、構築する際の重要なルールが書かれています。
iOS
ナビゲーションを含むiOSのすべてのUIのためのネイティブフレームワークはUIKitと呼ばれます。スクリーンベースのインターフェースを管理するためのいくつかのキーコンポーネントが入っています。
UIViewController – 表示されているそれぞれの画面をコントロールします。独立のビューには含まれない表示関連のライフサイクルコールバックやメソッドがあります。
UINavigationController – 戻るボタン等を表示するUINavigationBarを含み、UIViewControllersのスタックをコントロールします。
UITabBarController – そのUITabBarビューのタブに属するUIViewControllers、またUINavigationControllersをコントロールします。
さらに、モーダルでのスクリーン表示はUIViewControllerのメソッドが行います。
Android
画面の管理や画面ベースのナビゲーションのためのAndroidのコアUIフレームワークには名前がなく、単にandroid.appパッケージの一部です(詳細はこちら)。追加でUIをコントロールするためにコアフレームワークに加えて、マテリアルデザインライブラリやAndroid Jetpackもあります。
Activity – UIViewControllerのように、ビューの管理やライフサイクルコールバックや画面を管理するためのその他のメソッドがあります。App Bar (かつてはAction Bar)の表示や管理も含みます。
Fragment – それ自体のライフサイクルコールバックやその他の機能もありますが、Activityビューの子ビューと考えることができます。Activity内のビューの階級や紐付けられたロジックをコンポーネント化できます。
BottomNavigationView – UITabBarControllerのAndroid版です。Activityビュー内にあり、いくつものFragmentをコントロールし、ユーザーがタブをタップするときにそれらを切り替えます。
つまり、Jetpackのナビゲーションコンポーネントはナビゲーションを簡単に構築するツールを提供し、詳しく述べるとFragmentsの表示をその中でコントロールすることによってActivityのUIを管理します。BottomNavigationViewはNavigationでコントロールできるよう統合ができます。
AndroidでのUINavigationControllerにあたるものにまだ言及していないのにお気づきでしょう。直接的に相当するものはありませんが、Fragmentのスタックを管理するためにひとつのActivityを使いたいのであれば、スタックナビゲーションはFragmentManagerを用いて行うことができます。もしくは新しいActivityをもう一方の上に表示することができます。
React Nativeでのナビゲーションの選択肢は?
現在、React Nativeでのナビゲーションに対応する人気の2種類オープンソースライブラリがあります。React NavigationとWixのReact Native Navigationです。
React Native Router FluxやReact-Router Navigationも他の選択肢として考えられるが、結局はReact Navigationを使用しているので、この記事では詳しく説明しません。
もしくはReact Router Native等を使って完全にUIを最初から構築することもできます。しかし、利用できるUIコンポーネントがないので、UIドリブンなアプリケーションでなければおすすめはしません。タブバー、ナビゲーション(トップ)バー、モーダル等のデフォルトなしに構築しなければならないためです。
どちらが人気か、その理由
React Navigationは現在より人気です。GitHubでReact Navigationが16.9kスターでReact Native Navigationが10.9kスターであり(この記事を書いた時点で)、 東京のReact Native開発者のコミュニティでもそれが言えると思います。
React Navigationは中心的なReact Nativeチームによってより比重が置かれて使用が促されています。それがReact Native Navigationより人気である理由のひとつかもしれません。
加えて、React Navigationは特にモバイルアプリ開発経験のない初心者にとって始めやすいです。React Native NavigationはネイティブのXcodeやGradleプロジェクトやObjective-C、 Javaファイルを編集しなければならなく、少し複雑で面倒かもしれません。一方、React Navigationは単純にpackage.jsonに入れるだけです。この違いについては後で説明します。
React Native Navigationはすばやく簡単にReact Nativeプロジェクトを作成できることで有名なExpoで使うことができません。プロジェクトをイジェクトしない限りExpoではネイティブプロジェクトファイルへのアクセスができないためです。React NavigationはExpoテームから推奨されています。
しかし、React Native Navigationの方がフォーク数は少ないが、より閲覧されていることに言及しておくべきでしょう。閲覧者が高ければ高いほどより多くの開発者が重要なプロジェクトで使用している可能性もあり、少ないフォーク比率はコードベースへのカスタマイズや修正の必要が少ないと言えるかもしれません。
オープンイシューの数も類似していて、それはどちらのアプローチでも課題や複雑な点に直面していることを示唆しています。
使い方に違いはあるか?
2つのライブラリの主な違いはスクリーン上でのUI要素の描き方とスクリーン間のナビゲーション扱われ方です。
シンプルなアプリケーションを例にとって、1つ目のタブにスタックナビゲーターを内包し、2つ目のタブに別の画面をモーダルで表示する画面があるタブバーで考えてみましょう。記事の長さを考慮しiOSにフォーカスします。
React Navigation
簡単にいうと、React Navigationは上述したプラットフォームで利用できるナビゲーションフレームワークを利用しない純粋なJavascriptライブラリです。ナビゲーション(トップ)バー、タブバー等すべてのナビゲーションインターフェース要素はスタンダードなReact Nativeビューでネイティブにできる限り類似するようReact Navigationで描かれアニメーション化されています。
それゆえReact Navigationによって作られるUIViewControllers、UINavigationControllers、UITabBarControllers、ActivitiesまたFragmentsがありません。実際、React Navigationを使用しているアプリにあるUIViewController、ActivityもしくはFragmentは、新しいReact Nativeアプリケーションを作成する際、ルートReact Nativeビューをホストするために自動的に提供されるものだけです。
XcodeのUI hierarchy viewerを使い、iOSのUIツリーを見てこの主張を確認してみましょう。
画像でわかるように、 (React Navigationではなく)React Nativeによって作られたルートUIViewController以外、UIKitクラス、子クラスがない。全てのタブとナビゲーションバーはRCTViewsだけです (UIView子クラスとしてネイティブでレンダリングされたReact Nativeビュー)。
React Native Navigation
一方、React Native NavigationはネイティブUIフレームワークの周りをラッパーで囲むためにReact Nativeブリッジを使用し、React NativeのJavascriptランタイムを経由してプラットフォームナビゲーションフレームワークを利用できる抽象化レイヤーを提供します。
タブバーは実際のUITabBarもしくはBottomNavigationViewに、新しいスクリーンはUIViewControllersとActivitiesもしくはFragmentsになるということです。
これを達成するために、React Native Navigationは表示されるそれぞれのスクリーンに新しいReact Nativeアプリケーションを備えます。React Navigationを使用しているアプリは通常ひとつのReact Nativeアプリケーションのみが走っています。
React Native Navigationを使った同じアプリビルドを見ていきましょう。
UIKitフレームワーククラスを拡張する3つのコントローラークラスがあります。
RNNBottomTabsController UITabBarControllerの子クラスで次を含む
RNNStackController UINavigationControllerの子クラスで次を含む
RNNcomponentViewController UIViewControllerの子クラス
しかし、もうひとつ、、
状況が少し複雑になるが、最近開発された追加ライブラリにも言及しておくべきでしょう。
React Native Screensは新しい画面を表示するためにUIViewControllersとUINavigationControllersを利用し、React Navigationに統合されます。React NavigationのピュアJavaScriptアプローチとReact Native Navigationのフレームワークラッパーのアプローチの間と言えるでしょう。しかし、日が浅いためネイティブタブバーをまだサポートしていないようです。
どちらを使うべきか?
おすすめは、、、両方です!ディベロパーインターフェースの感覚を掴むためにそれぞれのライブラリを少し使ってみることをおすすめします。デザインへのユーザーインターフェースの動き方や感覚、そしてアプリのパフォーマンスの感覚を得ることです。
アプリの主な使われ方の構造、特にタブバーやスタック、モーダルを使ってプロトタイピングしてみることがいいと思います。それぞれのライブラリに慣れるまでそんなに時間はかからないと思います。React Nativeでの開発の重要な側面を理解すると思います。もし長い間サポートしていなかければならない重要なアプリであれば、個人的には数日間プロトタイピングしてみるのがいいと思います。
しかし、そうしたくない場合や、時間がない場合は、おそらくそのプロダクトは会社にとってあまり重要でない、もしくは趣味のプロジェクトであるのではないでしょうか。それゆえ、以下を考えてみたほうがいいかもしれません。
もしReact Nativeを始めたばかりである、またネイティブモバイル開発未経験であれば、Expoを使いすぐに軌道に乗ることができるReact Navigationで進めることをおすすめいたします。それでも十分だと思います。
もしプロダクトがとりわけ複雑で、それぞれのプラットフォームでの最適な体験を提供することを重要視する、もしくは一般的なモバイル開発経験があるのであれば、React Native Navigationを試してみることをおすすめします。クロスプラットフォーム開発経験者は、パラダイムを理解するので、最大限に利用する方法が直感的にわかると思います。複雑なプロダクトにはよりよいUIパフォーマンスに繋がる可能性が高いです。
Tacchiでは何を使っている?
React Navigation、React Native Router Flux、React Native Navigationをここ数年クライアントプロジェクトで使用してきました。React NavigationとReact Native Navigationがない時期にはNavigatorIOSも使用しました。そしてその後、消されました。
しかし、しばらくの間はReact Native Navigationを弊社のプロジェクトではもっぱら使っています。クライアントやプロジェクト的に強い理由がなければ、もしくはReact NavigationとReact Native Screensに顕著な進展がなければReact Native Navigationを使っていくでしょう。
アプリが成長してもパフォーマンスへの悪影響がないことと共に、プラットフォームでの最適な体験を提供することを重要視する人たちとしてAppleとGoogleによる素晴らしいフレームワークが利用できることが大きな理由です。この観点から、何年も正統的なiOS、Android開発を行ってきたことが功を奏したと言えるでしょう。
確かに、OSフレームワークによる制限のためReact Native Navigationは限度があるが、前述したプラットフォームのUIデザインガイドラインを遵守しなければならないことはお客様やユーザーに使いやすくネイティブ感覚なアプリを提供することにつながるため、個人的にはそれはいいことだと思います。