Android / iOS 両スマホアプリを開発するためには、一般的にはそれぞれKotlin (Java)/ Swift(Objective-C)で実装をする必要があります。しかし、クロスプラットフォームのアプリケーションフレームワークが誕生し、一つの実装で、両スマホアプリを開発することができるようになりました。現在、クロスプラットフォームのフレームワークでよく利用されているものとして、React Native とFlutter があります。どちらが良いフレームワークであるか、は分からず、そのため、どちらを利用すべきか迷うかと思います。そこで、本稿では、React Native とFlutter のパフォーマンスについて比較して、どちらが優れているかを検証したいと思います。
React Native
React Native は2015年にFacebook から発表されたクロスプラットフォームのアプリケーション開発のためのフレームワークです。言語はJavaScript であり、Web 開発で用いられるReact をもとに開発をされているので、Web エンジニアでも学習コストが低いと言われています。
アーキテクチャ
JavaScriptのコードはBridgeを介して、ネイティブのコンポーネントにアクセスします。そのため、UIはネイティブUIを利用することができます。しかし、JavaScriptのコードはネイティブコードにコンパイルされないので、アプリサイズやパフォーマンスが悪い、と一般的には言われています。
Flutter
Flutter は2018年にGoogle から発表されたクロスプラットフォームのアプリケーション開発のためのフレームワークです。言語はDart です。Dart はJava やC# に似た言語であり、それらの言語の経験があれば学習コストが低いと言われています。
アーキテクチャ
skia と呼ばれる2D レンダリングライブラリを利用して、Dart で実装されたUI をレンダリングします。そのため、UI は独自のUI となり、Android / iOS で同一UI となります。また、Dart のコードはネイティブコードにコンパイルするため、アプリサイズはあまり増加しないと言われています。
パフォーマンス検証
React Native、Flutter およびKotlin でHelloWorld アプリを実装しました。これらのアプリで、ビルド実行時間、アプリサイズ、アプリ起動時間、メモリ使用量を計測しました。
環境
- MacBook Pro
- CPU 2.4GHz
- メモリ 16GB
- バージョン 10.15.5
- Android Studio
- Arctic Fox バージョン 2020.3.1 Patch 3
- 端末
- Google Pixel 3a XL
- Android バージョン 12
ビルド実行時間
以下のコマンドを初回と2回目の実行時間を計測しました。(単位はs)
./gradlew bundleRelease
結果
考察
3つのアプリとも2回目の方が大きく減少しています。これは、キャッシュが効いているからだと考えられます。
Kotlin は他の2つに比べ、ビルド実行時間は短くなっています。これは、フレームワークがないので、コード量が小さく、余計なビルドが存在しないためだと考えられます。
React Native とFlutter を比較するとReact Native の方が初回のビルド実行時間は長いですが、2回目は短くなっています。これは、React Native では、巨大なフレームワークのJavaScript のコードをbundle するのが原因の一つであると考えられます。JS をbundle するだけの実行時間を計測したところ22秒掛かったことから、それを裏付けることができます。ただ、これ以外にも原因があるように考えられるので、調査が必要です。
React Native とFlutter には、ホットリロードの機能があるため、開発者にはあまり気にする必要はないかと思います。強いて言えば、リリース時にこれだけの時間待つ必要があるので、それがストレスになりますが、CI 環境をきちんと整備し、自動リリースできるようになれば、そのストレスもなくなります。
この検証では、HelloWorld アプリなので、この結果の差はフレームワークの差と言えますが、アプリケーションのコードが増えた時にビルド実行時間にどのように影響が出るのか、調査する必要があります。
アプリサイズ
aab ファイルを作成して、サイズを計測しました。(単位はMB)
結果
考察
Kotlin は他の2つに比べ、アプリサイズはとても小さいです。これは、フレームワークの巨大なコードがないためであると考えられます。
Flutter の方がReact Native より小さいです。これはFlutter ではDart のコードまでネイティブコードになっている一方、React Native では、JavaScript のコードはネイティブコードになっていないためである、と考えられます。
この検証では、HelloWorld アプリなので、この結果の差はフレームワークの差と言えます。ただ、アプリケーションのコードが増えても、Flutter とKotlin の差はこのまま変わらないが、React Native とFlutter の差は広がっていくのではないか、とアーキテクチャから推測されます。しかし、今回の検証ではアプリサイズに関する設定は初期設定のままなので、最適な設定をすることでもう少し差が縮まるのではないか、と考えます。
アプリ起動時間
以下のコマンドでMainActivity の起動に掛かる時間を計測しました。(単位はms)
adb shell am start -S -W com.example.TestProject/.MainActivity
結果
考察
Kotlin は他の2つに比べて、起動時間は短いです。これは余計な処理が挟まれないためである、と考えられます。
Flutter の方がReact Native に比べて起動時間が長いです。これは、ネイティブコンポーネントで画面を表示するのではなく、skia でレンダリングをする、という処理をしているためである、と考えられます。
React Native はKotlin と比較すると起動時間は長くなっていますが、あまり大きくはありません。これはネイティブコンポーネントを表示しているためだと考えられます。ただ、今回の検証ではHelloWorld アプリであったため、画面に表示されるコンポーネントの数が少なく、JavaScript とネイティブコンポーネント間をBridge する数が少なかったためでもあります。Bridge する数が増えると性能が劣化すると言われており、複雑な画面になると、起動時間が大きく増える可能性があります。
メモリ使用量
Android Studio のProfiler を利用して計測しました。(単位はMB)
結果
考察
Kotlin は他の2つに比べて、メモリ使用量は少ないです。これは、余計な処理やコード量が小さいためである、と考えられます。
Flutter の方がReact Native に比べて、メモリ使用量はとても多いです。skia でのレンダリングをする、というようなFlutter 独自の処理が入っているためである、と考えられます。これはNative にメモリを多く使っていることからも裏付けされます。
React Native はKotlin よりメモリの使用量が多いです。これは、フレームワークを含んでいるため、コード量が多いためです。
この検証では、HelloWorld アプリなので、画面にはほとんど何も表示されません。そのため、Graphics にはメモリがほとんど利用されていません。しかし、複雑な画面を表示するアプリだと、Graphics のメモリの使用量が増えるのではないか、と推測します。ただし、Flutter はskia でNative での描画になるので、他の2つよりGraphics のメモリ使用量が押さえられるかもしれません。検証が必要です。
まとめ
React Native、Flutter およびKotlin におけるHelloWorld アプリのパフォーマンス検証を行いました。当たり前ですが、全ての指標においてKotlin が圧倒的に優れていました。React Native およびFlutter は指標ごとに一長一短がありました。そのため、どちらが優れている、とは一概に言うことができません。
HelloWorld アプリは実践的なアプリとは言えず、より実践的なアプリだと差が縮まる指標があるのではないか、と推測されます。これは、追加で検証が必要だと考えています。
この検証がどちらのフレームワークを利用してアプリを開発すべきかを考える参考になれば嬉しく思います。