こんにちは。エンジニアリング事業本部の@gc_tech70です。 普段はNuxt.jsを使ってフロントエンド領域をメインに開発をしています。
現在、弊社の運営しているWebサービスであるスマートマットライトの管理画面をアプリ化したいという展望があり、その際にFlutterを使ってどの程度の要件を満たせるか技術検証したので、その知見を共有したいと思います。 私自身アプリを開発した経験はないので、基本的にWebエンジニア目線となっています。
まずアプリ化を検討した際の技術選定の経緯について、お話します。 今回はネイティブ(Kotolin,Swift)、 クロスプラットフォーム(ReactNative, Flutter)の中から選定しています。
前提として大きな要件としては以下が挙げられます。
ネイティブとクロスプラットフォームでは特徴が大きく異なるため、まずはこの2つについて比較していきます。
ネイティブのほうがOSアップデートに追従しやすく、パフォーマンスにも優れるため、リソースに余裕があればこちらを採用したいところではありますが、現状のリソース要件ではクロスプラットフォームの方が適しているため、今回はクロスプラットフォームを採用します。
ReactNativeのほうが現状では有名アプリの実績が結構あったり、Reactベースで書けるので、Vueを採用している弊社では比較的学習コストも低く対応できると思います。 さらにExpoという開発ツールで開発すれば、ネイティブコードを書けなくなるという制約の代わりにアプリ審査を通さずにアプリの更新が可能というメリットもあります。
Flutterは個人的に検証前から触っていたのですが、DartもJavaとJSの開発経験があれば、割と見慣れた記法なのでそこまで難しい印象はなく、学習コストに関してはReactNative > Flutterかもしれませんが、大差はないかなという印象です。
また、パフォーマンスの面ではFlutterもReactNativeも一長一短なようです。 https://recruit.gmo.jp/engineer/jisedai/blog/reactnative-vs-flutter-performance/
UIの面ではReactNativeはプラットフォームによって見た目が変わりますが、Flutterはどのプラットフォームでも統一された見た目になります。 それぞれのプラットフォームで最適化されたUIとなるのが理想的ではありますが、リソース的にどのプラットフォームでも統一された見た目となるFlutterの方が単一のデザインを再現するだけで済むので現状の要件ではFlutterの方が都合がいいように思います。
上記のようにFlutterとReactNativeではどちらかが一方的に優れているというわけではないですが(JSしか書きたくないということであればReactNative一択だと思いますが)、Githubスター数からも分かるようにFlutterの方が最近は勢いがあることやモバイルアプリに限らずWebやデスクトップなど複数のプラットフォームに対応できる展望があることから将来性の面も加味すると、Flutterに軍配が上がるかなというところです。
ということで今回はFlutterを採用してアプリ化が可能かどうか技術検証していくことにしました。 ※ちなみに検証中の開発体験が悪かったり、技術的なブロッキングポイントが見つかれば別の技術に変える可能性はあり、とりあえず試してみるというぐらいのスタンスです。
https://zenn.dev/tetsukick/articles/c297b6ee1e64397432e5 https://qiita.com/nskydiving/items/41e446ef5c821359ab79 https://macro-send.com/blog/reactnative https://bagelee.com/programming/react-native/react-native-apps-example/ https://qiita.com/tetsukick/items/a883f73b526eb2a63b8a https://qiita.com/nskydiving/items/c13c949cc17c6f980a67
機能的な要件は以下の通りです。
また、以下の非機能要件についても調査しました。
検証環境
※この検証は2020/12 〜 2021/1に検証した内容なので、現在のライブラリやOSのバージョンによっては内容が異なる可能性があります。
検証内容と結果を全部この記事に記述しようとしたのですが、ボリュームが大き過ぎて何の記事か分からなくなるレベルだったので、とりあえず今回はざっくりと結果だけ書いていきます。 それぞれの実装方法など検証内容の詳細については今後別記事として執筆していきたいと思います。
今回の検証にはこちらのライブラリを使用しました。 https://pub.dev/packages/barcode_scan
Flutterで諸々の技術検証を実施した結果、Flutterでも様々の機能の実装が可能なことが分かり、アプリ開発経験ゼロの自分でもある程度まともなアプリの実装が可能だということが分かりました。 特にUI的な面で強く、Webで実装できそうな機能要件の範囲ではネイティブと比べても大幅に実装工数を減らすことができそうです。
Flutterはホットリロード、公式ドキュメントの充実、エディタ(VSCode、Android Studio)の拡張機能を公式がサポートなど、開発体験はかなりいいように思いました。 また、UIコンポーネントのような感覚で実装できるので、UI面に関しては複雑なデザインを求めていなければマテリアルデザインで整ったUIが手軽に実現できる点が魅力的でした。(CSS嫌いな人にもおすすめできそう)
その他、Dartはオブジェクト指向言語で静的な型付けも可能なため、補完が効いてサクサク書けるほか、Widgetのオプションなどもドキュメントを調べなくても定義ジャンプすればざっくりどんなものがあるか知れるので、そういった点についてもとても使いやすい点だと思いました。
例えば、Container
classにカーソルを当てると、marginやpadding、width、height、colorなどが設定できることがエディタ上で分かります。
一方で気になった点として、Flutterは性質上、コードのネストが深くなりやすいのでチーム開発する場合には、他の言語と比べても特に可読性を意識したコーティングが重要だと思いました。
Flutterに限らずクロスプラットフォームという目線で言うと、iOSで独自実装の必要が出た場合、XCode以外でコーディングできないので、慣れてないエディタでコーディングしなければいけない点やXCodeがアップデートを頻繁に要求してきて、その度にストレージも40GBぐらいは空けておかないとアップデートできなかったりするので、苦労するポイントはそこそこありました。
Dartは静的型付けに対応しているので、TypeScriptみたいな感覚で書けますし、Flutter自体もReact,Vue,Angularなどを書いたことがあれば同じノリでコンポーネント(FlutterではWidgetと呼ぶ)作っていけばいいので、Flutterの記法にさえ慣れれば概念的には大分似ていると思います。
非同期通信もおなじみのasync, awaitを使う感じですし(axiosっぽいライブラリもある)、状態管理もhooksが使えるので(あんまり検証してませんが)、ある程度モダンな環境でWebフロントエンドの開発経験がある人であれば学習コストは低めだと思います。 一方でWeb開発者目線だとReact,Vue,Angularなどのフレームワークに馴染みがない方だと状態管理やコンポーネントの設計まで覚える必要があるので、慣れるまでに少し時間がかかるかもしれないと思いました。
また、ネイティブコードを書く必要がある場合には、Flutterに加えてKotolinやSwiftも結局覚えなければならないので、学習コストは上がると思います。 さらに要件によってはObjective-CやAndroid向けのJavaまで覚える必要があるので、そこまで行くと慣れるまで学習コストは高いと言わざる得ないかもしれません。 自分が触った感触ではSwiftやKotolinはオブジェクト指向の言語触ってればまあなんとなくは読める感じだったので、そこまで問題じゃないかもしれませんがObjective-Cの癖が強くて、どうやって書けばいいか分からず大分苦戦しました。
OS依存が強い機能では、同一ソースコードで複数のOSに対応できるクロスプラットフォームの強みを活かせず、OSごとに個別の実装が必要であったり、公式のライブラリが存在せず、サードパーティのライブラリだとメンテナンスが特定のOSのバージョンから止まってしまうなどのリスクもあり、ライブラリを使ったとしても最悪使えなくなった時の対策として、直接ネイティブコードを書いて同一の機能を自力で実装できるぐらいには実装方法をざっくり把握しておくことが必要だと思いました。 そのため、それぞれのOSのバージョンアップには常に警戒しておく必要がありそうです。
また、LwA(Login with Amazon)のようなベンダーのSDKを使いたい場合、現状ではほとんどFlutterに対応していることはないと思うので、それぞれのOSで個別にSDKをインポートして利用する必要があり、実装がかなり手間になってしまうようです。(場合によっては使用できない可能性もあるかもしれません)
ただし、これらの問題はおそらくFlutterに限らずクロスプラットフォーム全般に言えることなので、仮にReactNativeを採用したとしても同様の問題が発生すると思われます。
iOSのほうがAndroidに比べてセキュリティポリシー的に厳しい影響で、ライブラリもAndroidのみ対応しているものも多くあり、OS依存の機能が多い場合、iOSのほうがライブラリが使えない可能性が高いので、実装難度はiOS > Androidとなりそうな印象でした。
また、自分が参加したFlutterの勉強会ではAndroid開発者の方はKotolinやJavaではなく、あえてFlutterを使っていると言う人もいるぐらい開発体験がいいそうなので、AndroidアプリのみのサポートとなったとしてもFlutterを採用する価値はあるようです。
結論、弊社のスマートマットライトのアプリ化に対してもFlutterを採用することはできますが、弊社のプロダクトのようなOS依存の強い機能やベンダー独自のSDKを使用する要件がある場合には相応の導入、運用コストがかかるので、注意する必要がありそうです。
Flutterの採用を検討する場合、以下のような順番でおすすめできるかと思います。 1. OS依存の機能要件なし、AndroidとiOS両方のサポート 2. OS依存の機能要件あり、Androidのみのサポート 3. OS依存の機能要件あり、AndroidとiOS両方のサポート