Spica*

プログラミングの話。

Hello, Flutter! (各種フレームワーク間比較)

Getting Startedの記事ではありません。各種フレームワーク間のアーキテクチャを元に良し悪しを考えた記事です。

Flutter 1.0 is out!!

Flutterがついに1.0になったようです!

とはいえ、僕はFlutterを追いかけてはいなかったので、「お前が言うな」とか言われそうですが。

僕がFlutterを気になっている理由

僕がFlutterが気になっているのは、クロスプラットフォームアプリ開発ツール、という点だけではありません。それ以上に UIの描画を自前で行う というコンセプトがあるのが僕的に重要な点になっています。(ちなみに僕はあまりTwitterを見たりしていないので、流行りには疎めです)

クロスプラットフォーム開発のフレームワークというのは、今までにもたくさんありました。僕はAndroid/iOSのネイティブアプリ開発者ですが、ionic(当時は2.0でした)やvue.jsといったフレームワークも扱ったことがあります。それゆえに、OSのデザインとしての制約に関しては無視できない部分があり、ずっと"ちゃんと"クロスプラットフォームで良いアプリを作ることのできないむず痒い気持ちを抱えています。

ionicの事例

例えばionic。ionicはCordovaを基礎としたフレームワークで、Cordova上でAngularを動作させることでクロスプラットフォーム開発を行うフレームワークです。各プラットフォームに合わせた美しいコンポーネントが用意されており、少しのHTMLを書くだけで簡単にAndroid/iOSに合わせたデザインが適用できます。そしてLive Reload機能もあるため、ソースコードを変更するとすぐに画面に結果が反映される。まさに高速に開発できるフレームワークです。

僕はこのフレームワークを採用するのを過去に渋ったことがあります。ionicが心配だったのではありません。問題は、Cordovaがベースとなっている点でした。

Cordovaはご存知でしょうか。ネイティブアプリ上にWebViewを一枚表示し、そのWebViewとネイティブアプリ(AndroidだとJava, iOSだとObjective-Cソースコードを書く部分)間の共通インターフェイスを提供することでクロスプラットフォームを実現するフレームワークです。

このアーキテクチャには、決定的に問題のある点が一点ありました。ネイティブAnroidアプリ開発者はおそらくご存知でしょう。Androidは現在フォアグラウンドにあるアプリを快適に動かすために、「アプリをバックグラウンドに移した後、端末のメモリが不足した場合、現在フォアグラウンドにあるアプリ以外のアプリのActivityやプロセスを状況に応じて殺す」という仕組みがあります。これはOSのデザインの一部であり、設定によってなんとかViewを殺さないようにする、といったことは不可能です。

ionicはCordovaの仕組みに加えてAngularをWebView上で動作させるため、大量のメモリを食います。ここで、ionicアプリからIntentで端末にプリインストールされているカメラアプリを起動してみましょう。どうなるでしょうか。カメラはご存知のように大量にメモリを食います。Nexus 5Xのようなメモリの少ない端末や、Pixel 3のように大量のCPU/メモリを使用するカメラアプリの場合は、バックグラウンドプロセスをすぐに殺しにかかるでしょう。そして元のionicアプリに戻ったときには、Angularの動くWebViewは既に殺されており、アプリは最初からになります。当然、WebView上の画面のスタックはクリアされ、それを復元する術はフレームワーク側にはありません(僕の触った時点では少なくともそうだった)。

また、Cordovaには罠が多く、プラグイン制作に関しては多くの人がStackoverflowにお世話になったことでしょう。configがわかりにくく、プラグインのアンインストールに関しては多く人が一度はハマるところと思います。gitignoreがフレームワーク的に意識されていないのも、なにか心の中にひっかかったものを感じ続ける要因です。

また、UIのタッチレスポンスが遅い問題もあります。WebViewなので仕方がないでしょう。

こういった理由より、採用を渋っていました。結局のところ採用はしたのですが、上記の問題は杞憂ではありませんでした。

React Nativeの事例

React Native at Airbnbの記事を覚えているでしょうか。もし見ていなかった場合、ぜひ確認してみて下さい。

ちなみに僕はReactは良いものと思っています。disるつもりは毛頭ありません(ついでに髪の話でもありません!)。WebサイドではReactを少し使った経験があり、とても使いやすかったことを覚えています(React Native自体は使ったことがありません)。伝えたいのはionicと同じく、仕組みの話です。

React NativeはJavaScript Coreをバンドルして動作します(iOSはそうではないようですが)。それを使うことでJavaScriptでロジックを書くことを実現しています。JavaScriptはWebの進化によって多くの便利な仕組み(AltJSやテストツールなど)があり、高速に動作するので、とても良い言語と今でも思っています。

問題はUIの作り方です。React NativeはJavaScriptを経由して書くプラットフォームに存在するViewを利用してUIを描画します。つまり、同じコードでもプラットフォーム独自のUIの制約に縛られてしまうのです。例えば見た目を変えようとしても全く一緒にするには多くのコードを書くことになり、深いことをしようとするとネイティブプラグインを導入せざるを得なくなることもあるでしょう。この問題は、Airbnbの記事にも書いてあります("共通のデザイン言語システム(DLS)"の項目や"ジェスチャー"の項目)。

この問題はどうしても完全に解決はできないでしょう。Webの開発者がネイティブアプリを作るためのフレームワークなのに、結局JavaObjective-Cを覚えなければならなくなることが発生してしまう。これはアーキテクチャの問題です。

Xamarin

Xamarinもアーキテクチャとして、React Nativeと同じ問題を抱えていると考えています。C#よりXamarinの用意したインターフェイスの仕組みを通して、ネイティブのViewを生成して操作します。使用している言語やツールの問題ではありません。

Unity

React NativeやXamarinの問題がUIと言いました。UIを独自に作成する機能を持つ、Unityだったら問題ないのでは、と考えたこともあります。2Dだけでなく3Dも表現できる。表現力ではピカイチです。

しかしこの場合標準のUIコンポーネントが用意されていない、というのが問題です。全く同じ画面をAndroid/iOSで用意してあげる(まさにゲームのような)のであれば良いかもしれません。しかし、各OSを使用しているユーザは、ゲーム以外でその挙動を期待することはおそらく無いでしょう。また、dot-per-dotの美しいUIにしたい場合、viewportの設定など考えることが増えるのではないかという懸念もあります。

Flutter

話を戻します。僕はFlutterはここまでの各種問題をほとんど解決しているのではないかと思っています。 各問題に関して列挙しながら書きます。

  • Cordovaの懸念
    • Activityの復帰の問題
      • この記事を書きながら調べてみましたが、これは解決していませんでしたGoogle製なのに、このissueがfixになっていないのは残念でした。
      • ただし問題ではないかも、と思っています。このコメントで依頼されているように、常に今の状態を永続化しておけば、問題にはならないかもしれません。この問題は、僕は真っ先に調べるつもりです。
    • プラグインについて
      • Cordovaのプラグイン管理の仕組みは対応は半ば無理やりのようなものでした。まだ確認していませんが、問題がないことを祈っています。
    • タッチの遅さ
      • こちらも確認していませんが、そんな致命的な問題を残すとは考えにくいので、心配していません。
  • React Native, Xamarinの懸念
    • FlutterにはSkiaが入っており、UIを独自に描画する仕組みになっています。最悪、Widgetsを自分で作る場合でも、複数解像度を意識だけしておけば、DartだけできれいなUIが作れることでしょう。それぞれのOS向けに何かをしなければならない、といったことは起きないと確信しています。
  • Unity
    • FlutterにはUIコンポーネントが存在しているので、最初から独自にUIを作り上げる必要はありません。Material/Cupertinoが自動で振り分けられるという認識でいます。

Flutterについても、どうしても懸念として残ってしまう問題もあります。ionic以外に共通していますが、VMを内包しているのでフレームワーク側のバグでクラッシュしてしまうことがありえます。その場合、アプリ制作者である僕らは、issueに助けを求めるしか方法がありません。自分で直すのは、多くの場合人や時間的な都合で困難でしょう。

まとめ

いろいろ書きましたが、実はほとんどアーキテクチャしか意識しておらず、コードを書いていません。なので、面倒な部分も実は多いかもしれないな、と感じているところもあります。

もっとちゃんとFlutterのDocumentationを読んだ上で、業務でのこのフレームワークの使用を慎重に判断していこうと考えています!