モバイルアプリの開発フレームワークの選び方

## はじめに

2008年頃にモバイルアプリが登場して以来、モバイルアプリ市場はますます活性化しており、
モバイルアプリを構築するための手法やフレームワークといったものも常に進化し、新しいものが誕生しています。

本記事では、モバイルアプリの開発フレームワークを俯瞰し、各種特徴を比較しながらどのような選択肢があるのか説明します。

## モバイルアプリの分類

下の図のとおり、モバイルアプリはその開発手法やフレームワークによっていくつかに分類することができます。

なお、一般的にモバイルアプリとは「App StoreやGoogle Playなどのストア経由で配布され、デバイス上で動作するアプリケーション」のことを指し、Webアプリとは区別して語られることが多いですが、本記事では「モバイル端末上で利用可能なアプリケーション」という意味でWebアプリについても取り上げることにします。

![Mobile App Frameworks-Category.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42275/0743228d-2427-d892-6fe4-6ca7eefea448.png)

まずはそれぞれがどんな特徴を持つものなのか、みていきましょう。

### ネイティブアプリ

ネイティブアプリは、特別な開発フレームワークを用いず、構築対象のプラットフォームにネイティブな言語を使用して構築するアプリケーションを指します。
これはiOSアプリであればObjective-CまたはSwift、AndroidアプリであればJavaまたはKotlinといった言語を用いて開発する形になります。

### クロスプラットフォームアプリ

ネイティブアプリがプラットフォームごとにネイティブな言語を使用するのに対し、クロスプラットフォームアプリは単一の言語で開発を行い、フレームワーク等を用いて各種プラットフォームで動作するよう構築できるものを指します。

クロスプラットフォームアプリはその技術的な特性によりさらにいくつかに分類することがきます。
分類する上での観点としては、UIのレンダリング処理をどこが担うかという観点で分けることができます。

#### ネイティブ型

ネイティブ型のクロスプラットフォームアプリはネイティブのレンダリングエンジンを利用してUIを描画します。

代表的なフレームワークとしては2015年にFacebookが生み出した[React Native](https://reactnative.dev/)やMicrosoftの[Xamarin](https://learn.microsoft.com/ja-jp/xamarin/get-started/what-is-xamarin)が挙げられます。
React Nativeの仕組みとしてはJavaScriptで記述したコードが、各プラットフォーム上のJavaScriptランタイム（今までは従来のJavaScriptCoreを使用していたが、v0.70からは独自開発の[Hermes](https://reactnative.dev/docs/hermes)を採用）で動作し、JavaScriptからはBridge（ブリッジ）を介してネイティブのUIやAPIが呼ばれる形になります。

ネイティブのレンダリングエンジンを使用するということは、ネイティブアプリと同等のUIを実現できるということであり、これはiOSであればiOSユーザにとって、AndroidであればAndroidユーザにとって使いやすいUIを提供することができるということを意味します。

#### 独自レンダラ型

ネイティブのレンダリングエンジンを利用するネイティブ型に対し、独自レンダラ型はアプリ内に独自のレンダリングエンジンを組み込み、OSに依存せずUIを描画します。

代表的なフレームワークとしては、Googleによって開発されている[Flutter](https://flutter.dev/)が挙げられます。
FlutterではDartという言語を使用してコードを記述します。iOSやAndroidなどのネイティブアプリを構築する際は、Dartコードはマシン語（ARM）に事前コンパイル（AOTコンパイル）され、レンダリングエンジンを含むFlutter Engineとともにアプリケーションに内包される形になります。

独自のレンダリングエンジンを利用するので、OSに依存しない自由なUIやiOSとAndroidで統一的なUIを提供することができることが特徴です。

#### ハイブリッド（WebView）型

Webアプリとネイティブアプリの機能を融合させたという意味で「ハイブリッド」と言われており、Webの技術（HTML/CSS/JavaScript）を用いて開発を行い、WebViewと言われるアプリ内ブラウザを通じて機能を提供するアプリケーションを指します。一言で言えばアプリ内でWebアプリを動かすようなイメージです。

代表的なフレームワークとしては、2008年に誕生してからハイブリッドアプリ開発のフレームワークとして長い間親しまれていた[Apache Cordova](https://cordova.apache.org/)が有名ですが、最近はCordovaの代替として登場した[Capacitor](https://capacitorjs.com/)を利用するのが良いでしょう。

Cordovaはプラグインシステムが最新のネイティブテクノロジに追従できなくなっている問題や、ネイティブコードが直接操作できないことによりエラーの対処が限定的になってしまうといった問題によりやや下火となっていた印象ですが、これらの課題を解決する形でIonicが開発したものがCapacitorとなります。CapacitorはAngular, React, Vue.jsといった任意のJavaScriptフレームワークと組み合わせて利用することができるため、非常にWebエンジニアフレンドリなフレームワークとなります。

#### ガワネイティブアプリ

ガワネイティブアプリはハイブリッドアプリと同様にWebViewを利用して、サーバ上にホスティングされたWebアプリを読み込み、機能を提供するアプリケーションを指します。
ハイブリッドアプリとの違いとしては、ハイブリッドアプリがHTML/CSS/JavaScriptで構築されたWebアプリをアプリに内包するのに対し、ガワネイティブアプリはサーバにアクセスして取得するという点です。
ガワネイティブアプリの「ガワ」とは「外側」や「何かを包む皮」という言葉からきており、その名の通りアプリとしてはWebアプリを表示するための器だけがあり、実態は別にあることからこのような言い方をされています。

ガワのみを作る場合にもFlutterやCapacitorといったフレームワークが利用できるため、最近はガワをピュアにつくることも少なくなってきているかもしれません。

### Webアプリ

#### PWA (Progressive Web Apps)

PWAとはProgressive Web Apps（プログレッシブウェブアプリ）の略称で、WebサイトやWebアプリをネイティブアプリのようにインストール可能にする技術、及びその技術を用いて構築されたアプリケーションを指します。
2015年にGoogleによって提唱され、2018年にiOS SafariがPWAを支える技術要素の1つであるService Workerをサポートしたことで、国内でも注目され徐々に普及してきました。

PWAの特徴として[MDN web docs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Introduction#what_makes_an_app_a_pwa)で8つの特徴が挙げられてますが、その中でも通常のWebアプリとの違いという観点で3つの特徴を説明します。

* **Installable**  
App StoreやGoogle Playといったストア経由ではなく、Webサイトから直接インストールしてホーム画面にアイコンを設置することができます。
* **Network independent**  
Service Workerを利用してリソースをキャッシュすることで、オフライン環境下でもWebページを表示することができます。

* **Re-engageable**  
[Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API)及び[Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API)を利用してサーバからの通知をバックグラウンドで受信し、ユーザに対して通知を送る「プッシュ通知」の機能が実現できます。

このようにWebアプリをベースとしてネイティブ「風」な機能を実現することができるのがPWAとなります。

#### 通常のWebアプリ

通常のWebアプリについては、これまで紹介したものとは異なり、ブラウザアプリを通じて閲覧されるものになります。

## 登場時期

各種フレームワークが登場した時期は下図のとおりとなります。
見てのとおり、クロスプラットフォームフレームワークの中でもReact NativeやFlutterといったネイティブ型、独自レンダラ型のフレームワークが比較的新しめであることがわかります。

![Mobile App Frameworks-Timeline.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42275/111cb10f-6403-85f9-d483-fd99ec30fc28.png)

## 各種比較

![Mobile App Frameworks-Summary.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42275/14a8d5ce-e276-054a-6da1-d2ab4162f5a7.png)

#### 対応プラットフォーム

単一のコードで複数のプラットフォームに対応できるという意味で、開発効率や運用の観点からクロスプラットフォームアプリは大きなアドバンテージになり得ます。例えば、現時点でWebアプリしか提供しない場合でも、将来的にiOSアプリやAndroidアプリへの展開を見据えて、Flutterなどを利用してWebアプリやPWAを提供するという選択もありでしょう。

現時でどのプラットフォームに展開する必要があるか、将来的に展開していくプラットフォームはあるか、そしてそれらをどのようなスキルセットで構築していくのかを判断材料として選択していく形になると思います。

#### ネイティブ機能

フレームワークを選定する上でネイティブの機能をどれだけリッチに使用するかを事前に見極めるのは極めて重要です。
言わずもがなネイティブアプリを構築する場合は全ての機能がフルに利用できるため、アプリの機能要件次第ではネイティブ一択となるケースもあるでしょう。

React Native、Flutter、Capacitorといったクロスプラットフォームアプリは、プラグインを通じてネイティブの機能にアクセスできますが、公開されているプラグインがそもそも存在しない、機能が足りていないといった場合は、自分自身でプラグインを作成する必要があります。
プラグインの作成を行う場合はSwiftやKotlinといったプラットフォームネイティブなコードを書く必要があるため、開発効率、メンテナンス性の観点からはできる限り避けたほうが望ましいでしょう。（もし多くのプラグインを作る必要がある場合はネイティブアプリを検討すべきです。）
例えばカメラや画像・動画のライブラリ選択ひとつをとっても、UIをリッチにカスタムしたい場合は既存のプラグインでは対応できないケースが多いです。単純に機能自体が使える、使えないだけで判断するのでなく、どこまでカスタムできるか事前にきちんと調査した上で判断することが重要です。

PWAやWebアプリについても、カメラや位置情報などにブラウザのAPI経由でアクセスすることが可能です。ただしAPIのサポート状況や仕様は各種ブラウザに依存するため、開発者からはアンコントローラブルな領域となります。例えばカメラにおいては画質を細かくコントロールできないといったケースがあります。

#### パフォーマンス

一般論としては、処理に余計なレイヤが挟まらず端末自体の性能をフルに活用できるという意味で、ネイティブアプリが最も優れています。
クロスプラットフォームアプリとしては、計測しないと一概には言えませんが、WebView依存するハイブリッド型やガワネイティブよりも、ネイティブ型や独自レンダラ型のほうが優れているでしょう。PWAやWebアプリもブラウザから動作するため、ネイティブアプリと比較すると遅延が発生し、バッテリーの使用量も多くなります。

ただしこれらはあくまで相対的な評価であって、根本的にハイブリッドアプリやWebアプリだからといって使い物にならないということではありません。重要なのは構築するアプリがどの程度のパフォーマンスを必要とするかということです。
３Dゲームや動画変換などCPUハードな処理を行う場合は高いパフォーマンスが求められますし、シンプルなCRUDアプリであればあまり気にする必要はないでしょう。

#### 流入経路

ネイティブアプリ、クロスプラットフォームアプリがApp StoreやGoogle Playといったストア経由での流入になるのに対し、PWA及びWebアプリはWeb検索経由での流入になります。

不特定多数のユーザに広めたいアプリを提供するのであれば、ストアでの提供、もしくはストアとWEB両方の経路での提供を行う必要がでてくるでしょう。その場合は、モバイルプラットフォームとWebプラットフォームの両方に対応できるクロスプラットフォームアプリで展開を行うのが効率的かもしれません。
一方で利用者が限られている to B向けのアプリであれば、ストア経由で配信する必然性は大きくないため、PWAやWebアプリのみで提供を行うという選択も考えられます。

#### 更新性

更新性については、アプリを修正した場合に審査が必要かどうかという点が大きなポイントとなります。

ネイティブアプリやクロスプラットフォームアプリはストアに公開されるため、ストア上のアプリを更新する際には基本的に（Enterprise Programなどで社内配布のみを行う場合を除き）審査必須となります。審査に想定外の時間がかかったり、予期せぬリジェクトが発生したりなど、Webアプリに比べると更新のハードルが高いという点は認識しておいたほうがいいでしょう。

ただし、クロスプラットフォームのフレームワークのReact NativeやCapacitorはOTA（over-the-air）アップデートに対応しているため、ストアの審査を通さずにアプリケーションをアップデートすることも可能です。OTAアップデートとはアプリケーションのリソース（JavaScriptコードなど）をインターネット経由で取得し、ロードすることでアップデートを可能にする方法です。ガワネイティブも必然的にこのようなアップデート方式となります。

#### 技術成熟度

Webの技術やネイティブの技術は十分に枯れているということができると思います。
ベストプラクティスやノウハウも多く蓄積されており、エコシステムも十分に成熟しているため、技術選定におけるリスクは低いと考えられます。
一方でReact NativeやFlutterは比較的新しい技術であり、フレームワーク自体に対するドラスティックなアップデートも行われているため、常に最新の状況をキャッチアップし、試行錯誤しながら進めていく必要があります。
特にReact Nativeは本記事執筆時点で最新バージョンが0.7とまだメジャーバージョンのリリースが行われていないため、破壊的な変更が入る可能性は大いにあります。

#### エンジニアの調達性

エンジニア市場においては、iOSエンジニアやAndroidエンジニアよりも圧倒的にWebエンジニアの数が多いです。
開発や運用リソースを外部調達する場合などは、このあたりの調達容易性も考慮してフレームワークを選定する必要があります。


## トレンド

最後に、あくまで参考程度となりますが、各種フレームワークのトレンドも見てみましょう。

下記は[statista](https://www.statista.com/)によるクロスプラットフォームアプリフレームワークの利用率調査となります。[^1]
やはりここ数年はFlutterの勢いが大きく、次いでReact Nativeが人気という状況です。
![statistic_id869224_cross-platform-mobile-frameworks-used-by-developers-worldwide-2019-2021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42275/50265892-90a0-be90-6556-72dc226dcb84.png)


下記は[State of JavaScript](https://2021.stateofjs.com/en-US/)の調査によるモバイルとデスクトップアプリ向けのJavaScriptフレームワークの満足度[^2]となります。
JavaScriptを対象としているのでFlutterなどのFrameworkは登場しませんが、使用率、満足度ともにReact Nativeが高い数値を記録していることがわかります。またCapacitorについては使用率こそ低いものの高い満足度を記録しているため、今後認知度が高まればより利用されていく可能性はありそうです。

![mobile_desktop_experience_ranking.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42275/7d9f4d8e-6494-993f-f3ea-1d52ca0df02d.png)


[^1]: 引用元: https://www.statista.com/statistics/869224/worldwide-software-developer-working-hours/
[^2]: 引用元: https://2021.stateofjs.com/en-US/libraries/mobile-desktop/