クロスプラットフォーム開発環境の技術選定に向けた調査をしてみた

はじめに

アプリ開発支援部の小鍋です。

約2ヶ月ほどかけて、スマートフォンアプリのクロスプラットフォーム開発環境の調査を行った記録と、その感想をご紹介します。

今回の調査対象は、

です。 R/NとFlutterはここ数年で最も使用されているクロスプラットフォーム開発環境です[statista]。そのためこの2つを調査対象として選定しました。 KMMについては、私がXamarin.Nativeの開発に携わった経験を踏まえて1年ほど前から注目していたため今回の調査対象に組み入れました。詳細は巻末で紹介します。

今回の調査の目的は、「Xamarinに代わるメインとする代替のクロスプラットフォーム開発環境を選びたい」 というものです。

過去のプロジェクトに携わった経験からPJメンバーの納得感を重視して調査をすすめることにしました。 そのプロジェクトで採用されていた技術に対して納得感があまりないという経験があったため、技術選定においては納得感が重要な立ち位置にあるのだと仮説を立てて進めていきます。

技術選定の進め方について

技術選定については色々な取り組み方があると思います。技術選定に携わることが今回で初めてだったので自分なりに進めていくことにしました。今回は実際に開発したことのあるアプリを模倣したものを作りながら進めることにしました。その経緯を説明します。

理想的な進め方は、すでに有識者がいて様々な論点で議論することです。弊社はAndroidまたはiOSのネイティブアプリやXamarinを用いた開発がメインであったため有識者がいません。そのため、他の方法を考える必要がありました。

今回与えられた期間が2〜3ヶ月ほどでしたので、「いかに少ない学習・調査期間で技術選定に移るか」を考えました。単にドキュメントを見てポイントを比較するといったやり方がすぐに思いつく方法です。しかし、実際に技術を使用する場合のイメージが付かず、具体的な回答をすることが難しいためもう少し念入りな調査を行う方法を検討する必要があります。

そこで、各調査候補であるサンプルアプリを作成することを検討しました。しかし、チュートリアルにあるようなサンプルアプリを作るだけでは、それぞれのプラットフォームにある特徴的なメイン機能や利点になる機能しか触れることができません。実際に開発を行う際もチュートリアルだけの知識ではどうにもならない部分が多くあると考えているため、あえてチュートリアルへの取り組みよりも難易度を高くすることを考えました。

そこで、実際にネイティブで開発したことのあるアプリケーションと同じようなものを作ると決めました。

理由は下記のとおりです。

  • サンプルアプリの仕様を決定するための工数がかからない
  • 当時の記憶をたどりながら進めていくことでネイティブアプリとの開発体験を比較することができる
  • 実際の要求をアプリケーションで実現するという実際のプロセスを直接経験することができる
    • そうでなければ、「作れるものしか作らない」というエンジニアの独学にありがちな問題に陥ってしまう。

もちろん模倣するときに全ての機能を盛り込むと大変なため、それぞれ採用する上で懸念となる観点を決めました。例えばWebViewが簡単に実装できるのか?やテーブルに相当するものを簡単に作ることができるのか?などです。

その観点を一通り満たすような機能のみを抽出し、サンプルアプリとしてそれを作成します。 ただし、デザインについてはほとんど妥協せず、「いかにデザイナーの要求を忠実に再現できるか」を目標とし、それぞれのプラットフォーム環境の開発体験の感覚を掴むことにしました。

クロスプラットフォーム開発環境の比較まとめ

調査した結果の概要を紹介します。

React Native

一言で「React」

Reactはフロントエンドのフレームワークの中でトップレベルに人気の高いフレームワークです。 私もReactが好きで、jsxがもたらす開発体験はその他のものよりも群を抜いて軽快であると感じます。 もちろんR/NはReactの技術の上に存在するプラットフォームなので、同様の開発体験を得ることができます。フロントエンド技術のなかで生き残ったReactという技術をスマートフォンアプリに展開したいという考えであれば使用することを検討していくべきだと思います。

主な特徴

  • 飽くまでもJSがOSのNative APIとのブリッジを担っているだけなため、ネイティブUIとして構築することができる
  • Expoという公式とは別のコミュニティを抱えている
  • ほとんどReactと変わらないため、Reactエンジニアに設計やDevOpsのサポートを依頼できる
    • ※UI構築に関しては、HTML/CSSと考え方が異なる点があるので注意が必要 (flexなど)
  • JSや直感的に記述できるjsxで記述されているため、学習コストや構築コストが低い。

採用を検討すべき主な要因

  • Reactに慣れている人がメンバーに多い
  • プロジェクトのフロントエンド・バックエンドがjsを採用している
    • ソースやナレッジの共有が期待できる

Flutter

一言で「マテリアルデザイン」

マテリアルデザインというGoogleが提唱したデザインフレームワークがあるのはご存知かと思います。マテリアルデザインの仕様がまとめられているmaterial.ioのなかで、実際にFlutterの開発を前提とした記述もありデザインフレームがその存在を認めているということは大きな強みだと思います。デザインフレームワークの成長にFlutterが追従していくという強い期待が感じられます。

主な特徴

  • マテリアルデザインを強力にサポート
  • Dart言語を採用
  • 標準のデバッガーがかなり作り込まれている
  • Widgetの実装が他の技術に比べて独特なため、慣れるのに時間がかかる
  • Android Studioが使える
  • CodeLabに学習コンテンツが用意されている

採用を検討すべき主な要因

  • マテリアルデザインに準拠する場合
  • 現在最も人気であるという強みを活かす(採用、動機)
  • 技術のキャッチアップが得意なメンバーがいる
  • 環境構築や開発体験の向上に関心の高いメンバーがいる

KMM

一言で「ネイティブ開発と仲良し」

KMMはJetbrainsが開発したAndroidとiOSで共通になっているロジックをまとめあげることができるようにするためのプラットフォームです。当然iOSはSwiftやObjective-Cで開発されているため、Kotlinで定義されたインターフェイスを読み取ることができません。そのため、KMMにはKotlinをObjective-Cにトランスパイルする仕組みが提供されています(参考)。 そのトランスパイルの接続さえ済ませることができれば、基本的にはネイティブ開発とほとんど変わらずにUIを構築することができます。

実際に開発してみると、Androidエンジニア単独、iOSエンジニア単独だけではどうしてもできない作業があったり、そもそも導入するためのナレッジが少なかったり、エラーが発生したときに問題解決に時間がかかったりするという問題が目立つためまだまだKMMの成長を待ったほうがよいのかなと感じます。

主な特徴

  • 「iOSからKotlinで書かれたコードを呼び出しすることができるようにするためのプラットフォーム」と捉えて問題ない
  • 開発環境、ビルド環境の整備が完了してさえいれば、iOSエンジニアはネイティブの開発と特に変わりなくUIの開発をすることができる。
  • ネイティブ開発の資産をそのまま移行することができる。

採用を検討すべき主な要因

  • すでにネイティブでの開発をしており、保守フェーズ等で開発コストの削減を行いたいという要求がある
  • 複数アプリ間で共有可能な機能が想定されている
    • 例) 自社共通IDへのログインライブラリなど
  • アプリ側で抱えるロジックが複雑になることが想定されるが、クロスプラットフォーム環境を採用するリスクが高くネイティブアプリでの開発を行わなければいけない場合

技術選定を振り返って

技術選定の活動を振り返って感じたことをいくつかピックアップして紹介します。

「データ」が極端に少ない

最終的に技術選定に必要な評価軸を洗い出しましたが、「言語化できて、定量的に評価可能で、意味のある」評価軸(例:Githubのスター数)は極端に少ないという結果になりました。 実際、「このようなアプリを作りたいのだけど」と聞かれて初めて言葉になるような言語化できない領域の知識がサンプルアプリの作成を通じて蓄積されたように感じました。

そのため、サンプルアプリを作成する取り組みは非常によかったと考えます。定性的な情報についてもきちんと収集していくことで納得感を持った説明をするための材料に繋がりました。

OSSコミュニティの大きさが十分にあれば、「できないことの少なさ」がある程度担保されると思われる

技術選定の調査に取り掛かる前は、何ができて何ができないのかを並べてできないことが少ないものを選ぼうくらいの気持ちでいました。しかし、特に機能面において「Flutterにできて、R/Nにできない」といったようなことがほとんど見受けられませんでした。公式がサポートしていなかったとしても、有志がOSSとしてそのライブラリを公開しているからです。

そのため、「OSSコミュニティの大きさが十分にあれば、できないことはあまりない」という仮定に対して合意をとった上で技術選定を進めていくと効率的に進めていくことが可能だと思います。

Webで調査した結果と、自分で調査した結果はあまり変わらない

Webで調査すると、選定結果が公開されていることがとても多いです。 あえて会社の一員として先入観を捨てての取り組みを行いましたが、結局Webの調査で出てきた選定結果とほとんど変わりませんでした。

そのため、技術選定については時間が足りないのであればWeb上にある意見を参考にしてもよいかもしれません。

また、実際の取り組みでは好みの問題による先入観と調査結果では結果が変わりました。サンプルアプリを作る上で、やっぱりこの技術のほうが作りやすいんだなあと感じとることができ、先入観を払拭することに繋がりました。

クライアントサイドの技術選定は難しい

サーバーサイドであれば特に可用性や速度、セキュリティなどの具体的で定量化できる領域が重視される傾向にあるため、技術選定の際に明確な判断基準を立てやすいと思います。

しかし、アプリケーションにUIを構築するようなクライアントサイドの開発では、実際にどのようなアプリケーションを作成するかで大きく必要な機能が左右されます。単にユーザーに情報を示していくだけのアプリであるか、WebViewを使い外部システムとの連携を多く行うのか、端末固有の機能と連携して物理的なユーザー体験をもたせるのか、など、様々な要求が来ることを想定する必要があります。

その中で全社的に推し進めていく技術を選定するというのはかなり判断が難しいと思います。

技術選定は納得感が重要かもしれない

過去私自身が参画していたプロジェクトである技術が採用されていましたが、「なぜその技術にわざわざしたのか」がわからないような状況になってしまっていました。 そのため、「他の技術を採用していればもっと快適に開発ができただろうな」と思うことが多々ありました。

こうした現状が起きている理由として、選定された技術に対して納得感がないことが挙げられると思います。 技術選定においても、「新しく参画したエンジニアに対して、納得感をもたせることができるかどうか?」という観点をメインにして行うとより明確に進められると思います。

技術選定だけでなく、選定された技術の行く末を

今回の技術選定の活動を通じて常々感じていたことがあります。

それは、「技術選定の活動に力を注いではみたが、それよりも『選定された技術に対する今後のキャッチアップと製品ライフサイクルを見守って対処していく活動』のほうがより重要ではないのか」ということです。

選ばれた技術に対してきちんとキャッチアップし、いつかは衰退するかもしれないという意識を持って開発を進めていくことが重要だと思います。また、その選定された技術に応じた体制をきちんと整えて維持していくことが必要だと思います。

そういう意味では、結果として、技術選定の活動を通して得られた知見はその体制作りに大きく活かすことができるように思います。 ただ選ぶだけではなく、仮に選ばれたとしたらどのような体制が必要なのか、どうキャッチアップしていけばいいのか、廃れたときはどうするか、についても同時に検討しておいたほうがよいのではないでしょうか。

おまけ

私が考えたクロスプラットフォーム開発におけるKMMの優位性

多くの人がイメージする「クロスプラットフォーム開発環境」は、UIも一つの構成で開発していくものだと思います。 ただし、それはいくつかリスクを伴います。

※「ネイティブ」はAndroid/iOSのネイティブ開発のことを指します。

  • OSが推奨するUXを提供できない。
  • OSごとに画面や機能を変えたい
  • ネイティブに比べ情報や事例が少ない

AndroidとiOSそれぞれ固有の機能を別個に実装する場合は、それに伴ってUIを変更する必要があります。OSごとに機能を切り分けることは基本的に可能ですが、コードや設計が煩雑になるリスクがあります。 頻繁にOSごとにUIや機能を切り替えることが想定されている場合は分岐が多いコードになり、全体的に読みづらくなります。

ネイティブAPIに100%アクセスできない限りはそれぞれのプラットフォームが提供する粒度でしかUIをカスタマイズできません。ネイティブが提供するUIコンポーネントは、デザイン標準に対して自動的に最適化する仕組みが備わっているためそれを享受することができないリスクがあります。 また、Flutterのように独自のレンダラーを採用している場合はそれが顕著になります。

2022年9月現在では少なくとも、ネイティブのほうがクロスプラットフォームよりも情報が多いです。StackOverflowの質問件数をAndroidとFlutterで比較すると10倍の差があります。

このように情報が少ない場合は、情報を見つけるための時間がかかり、コストが膨らむ可能性があります。 また、情報がない場合は機能の実装を諦めたり、クロスプラットフォーム環境のソースコードを読んで解決したりする必要があるかもしれません。

KMMはこのリスクをすべて解決します

KMMはiOSとAndroidのUIをそれぞれ別に開発することを可能にしています。iOSはUIをSwiftで記述し、AndroidはUIをKotlinで記述できます。その違いをXcode上のパッケージ管理ツールを通じて解決する仕組みがKMMにあります。AndroidとiOSで共通化可能なロジックに関してはKotlinで記述します。Androidは通常通りGradleから読み込み、iOSはパッケージマネージャー(CocoaPodsなど)を経由してObjective-Cとして利用可能にできます。

もちろんAndroidとiOSのUIの記述に関してまとめるなど、OS間のコードの共有率上げるためにはチャレンジングな取り組みが必要ですが、先程あげた上記のリスクに関しては問題なく解決させることができます。