iOSネイティブアプリ開発者から見たFlutter

2018年8月 Release Preview 1 時点での所感

mono 
Flutter 🇯🇵

--

GCP(Google Cloud Platform)やmBaaSのFirebaseが人気を博していたり、Google I/O 2018も大いに盛り上がるなど、最近のGoogleの開発者ウケがかなり良く素晴らしいサービスを連発しているなと感じていたのもあって、5月くらいから Flutter に取り組み始めました。まだ特にFlutter製のアプリリリースなどはしていませんが、それを見据える程度には本気でやっています💪

なぜFlutterに興味を持ったか

FlutterはAndroidアプリ開発者ウケの方が良くて、iOSネイティブアプリ開発者が本気で触っている事例を国内ではあまり見聞きしません。そのためか、周りからも「iOSネイティブアプリが作れるのになぜFlutterにも手を出すの?」のようなことを聞かれることがちょくちょくあります。まずはそのあたりから詳しく述べていきます。

一番初めのきっかけはDroidKaigi 2018の発表

DroidKaigi 2018 用のiOSアプリがFlutterで作られていて、

さんのこちらのスライドを見たりPodcastを聴いて知ったのが初めかもしれません。

それまでもFlutter関連情報を見聞きしていた気もしますが、興味が薄すぎて無意識にスルーしてしまっていた気がします。
(FlutterはGoogle I/O 2017直前にv0.0.6 がリリースされていて、Android界隈のアーリーアダプターはその頃から触っていたはずです。)

ただ、このDroidKaigiの話を聴いたあとも正直「ふーん、Flutterという新しいクロスプラットフォーム開発フレームワークがあるのか」くらいにしか思わずでした(React NativeやXamarinと同程度に適当にウォッチくらいはしておこうかな、程度の興味)。

5月のGoogle I/O 2018明けにFlutterと戯れた

それからしばらくして、5月のGoogle I/O 2018明けの週末にFlutter入門してみました(ちなみにゴールデンウイーク中はFirestoreの記事を4本書いてました)。

ちょうど大好評だったGoogle I/O 2018が終わった後で、そこでもFlutterが勢いがある様子だったので再び興味が出た気がします。この時点で、Beta 3がリリースされた直後でした。

その前にも2018年の2月・4月と、beta 1・2がリリースされてけっこう盛り上がっていたようですが、iOS・Swift界隈にいたためかそういう空気に気付けずでした。

この時点で、beta品質が許容できればプロダクション利用もまあまあありかな、というレベルに達したということだと解釈しています。

また現時点では、Release Preview 1までリリースされています(正直、単に表面的なバージョン表記が違うだけでbetaとの決定的な差はよく分かりません)。

正式リリースは来年予定のようですが、それもあくまでGoogleが予定している1.0クオリティに到達したかどうかの目安であって、現時点でも利用者の判断次第で十分プロダクション利用可能な状態です(Google自身もFlutter製のAdWordsアプリリリース済みですし)。

We are targeting a 1.0 release within the next year, but we will continue to adjust the schedule as necessary.

Ready for Production Apps: Flutter Beta 3

[2018/12/6追記]

このあとRelease Preview 2を経て、2018年12月4日のFlutter Live ’18 にてFlutter 1.0がリリースされました㊗️

話は戻ってこの5月の休日の僕の活動としては、それまでのAndroid Studioに加えてVSCode(Visual Studio Code)でもFlutterの開発ができるようになったということなので、お手軽そうなVSCodeでセットアップしてこのcodelabを写経してみました。

第一印象は、Dartコードですべて書く割り切りが特徴的だなと思いつつ、特に好印象では無かったです。Dartはまあまあ書きやすいものの、Optionalが無いなどの不満点もまあまあ気になりました(今でも気になっています)。ただ、今風のシンプルに書ける静的型付け言語な感じではあるので、まあまあ良いかなと思いました。また、言語仕様がシンプルなためかサクサクと記述できる書き味の良さも感じました。

また、Cupertino Widgets(Apple本社のあるクパチーノ由来の命名)を使えばiOSネイティブアプリっぽいアプリを作れることを知ったものの、見た目や動きがまだまだ偽物っぽいなと思いました。

ただ、同じGoogleによる開発なこともあり、Androidアプリならネイティブに遜色無いものを作れるかも?ともその時点でなんとなく思いました。

触っているうちにじわじわとFlutter沼にハマってきた

そうやってFlutterに触れたところ、まだまだ未知数ながら可能性がありそうな気がじわじわしてきました。また、Flutterの思想やアーキテクチャーなどにも興味が出てきて、ドキュメントや関連記事なども日常的にちょくちょく読んでいた記憶です。

そして、Firebase使って実用的なアプリ作るとしたらどういう感じかな?と思ってこの動画を観たあたりから、毎日のようにFlutterについてつぶやくようになってきました( ´・‿・`)

そうしてFlutterが少しずつ手に馴染んでくると、勉強したり書いたりするのがどんどん楽しくなってきて、本業以外は大体Flutterで遊ぶようになってきた気がします🤔
([追記] 2019年4月からは本業として取り組めるようになりました。)

というわけで、興味を持ったきっかけや今も取り組み続けている経緯の説明でした。ここから、今ではFlutterをどう評価しているかなど説明していきます。

Flutterへの評価

以下の通り、僕はかなり高く評価しています。

高い生産性

モバイルアプリ開発ではビルド時間が長いことによる生産性低下が問題になりがちですが、FlutterではHot Reload/Restartによって基本的にビルドは初回のみで済みます。開発環境・プロジェクト規模によって差はあるはずですが、だいたい次のような短い時間でコードの変更がアプリに反映されます。

  • Hot Reload: 1秒未満(差分が少ない時・大体こちらで済む)
  • Hot Restart: 数秒程度(差分が多い時・詳しくは下記の Limitations 参照)

また、すべてDartコードで記述することも高い生産性に寄与していると感じています。以下の記事でFlutterのCons(マイナス点)として There is no JSX など挙げられていることに対しての反論リアクションが大量にありますが、それらと完全に同意見です。

簡単に言うと、コードだけで書くが故にやりたいことをそのままシンプルに書ける、という感覚です。実装したい機能に対するコード量がかなりコンパクトに済む印象です。また、WidgetをネストさせてUIを記述していきますが、個人的にはXMLのネストと大差無い感覚でUIのDSLなどと比べて書きやすさも可読性もあまり劣らないと感じています。さらに、Dart 2でnew/constを省略可能になったこともそれらに大きく貢献しました。

また、コードなのでネストが深くなったらメソッドや別Widgetなどに逃すのも楽々できます。その他、UIのリファクタリングがすごくやりやすいです。

まとめると、次のような感じでしょうか。

  • Hot Reload/Restartによってとても速いサイクルで実装を進められる
  • UI含めてDartコードで書くという割り切りがうまく機能していてUI実装効率が良い

バランスのとれたDart言語

型推論があるなど全体的にモダンな静的型付けな印象のDartですが、特に以下が普段普通にコードを書いていて嬉しいところだと思っています。

  • async/await(Promiseと似た非同期型のFuturesの結果を同期的に取得できるキーワード)が言語機能に組み込まれている
  • Streams(Rxの簡易版みたいなもので複雑な非同期処理には別途rxdartパッケージ併用が必要)が標準パッケージに含まれている
  • Cascade notation(.. )によって、あらゆる既存メソッド・プロパティなどをメソッドチェーン的に扱える
  • dartfmt が言語とセットになっていて、書き方を簡単に揃えられる(analysis_options.yamlによって細かいカスタマイズも可能)
  • 標準パッケージが充実していて、野良パッケージが必要な場面が少ない

一方、次の点などはネガティブに思っています。

  • Optionalが無い(quiver パッケージに一応あるものの言語に組み込まれていない)
  • 末尾に ; が必要など古臭く感じられるところがちらほらある
  • Swiftだと括弧が不要な箇所にも書く必要があったりなど、自分の好きな言語より面倒な部分が気になりがち

また、似たような既存言語があるのにわざわざDartを覚えるの怠いという意見もありそうですが、このあたり読むと大体納得できるのでは無いでしょうか。

という感じで、Dartにはまあまあ気になるマイナス面もありつつ(それらは今後改善予定あり)、総じて気に入っています。
また、Dartは似たような最近の言語に慣れていれば学習コストはかなり低く、Flutter自体の学習コストが支配的になるはずです。初めはDartの細かい仕様はあまり気にせず適当に勘で書きながら分からないところや興味出た箇所を随時調べる、とかで十分な気がします。
([追記] このあとしばらく付き合った結果、Dartはこれまで触れてきたプログラミング言語の中でトータルで1番快適に感じています。)

初めの学習コストはやや高め

Dartはともかく、Flutterの宣言的なUIお作法に慣れたり、用意されているたくさんのWidgetsの把握など、実用的なアプリを作るにあたって初めに詰め込むべき事項が多めに感じます。

また、手続き的な記述のUIなら、何か所望のことをしようとした時に少し汚い書き方を妥協しさえすればどうにでも書ける感がありますが、Flutterの場合はきちんとお作法に従った書き方にしないとまともに動かなかったりします。
(Flutterならではの特殊なルールがたくさんあるというわけではなく、ライフサイクルの流れをきちんと把握して然るべきポイントに適した処理を書く必要が強いということです。)

ある程度慣れたら開発速度がグンと加速すると思っていますし、React NativeとFlutterともに詳しい方がそういう評価をしていたのも心強いです。

ちなみに、上の動画はつぶやいた時のものが消えてしまって、こっちに再アップロードされていました。

Googleの公式ドキュメント・学習資料などが充実していて分かりやすい

「Flutterの効率良い学び方」で色々紹介予定しましたが、Googleの公式ドキュメント・学習資料などが充実していて、かつ分かりやすいです。

また公式ドキュメント以外にも英語記事は大量にあるので、少し困っても調べれば大抵なんとかなります(黎明期の海外製の技術にありがちですが日本語記事はかなり少ないです)。また、定義を辿ってソースを直接読めるのも良いです。ソースもコメントも比較的分かりやすいです(ソースのシンプルさは意識していると中の人も言っていました)。

FlutterでiOSネイティブアプリを作る時の戦略

そろそろ、iOSネイティブアプリ開発者ならではの目線で書いていきます。

[2018/12/6追記]
以下でFlutterで見た目的にiOSネイティブアプリそっくりなものを作ることは難しいと評価していますが、そのあとの数ヶ月の改善でかなり良くなったと思います。開発者のシビアな目線だとまだ差が分かったりしますが、一般ユーザーがネイティブアプリと区別つかないレベルのものをFlutterでほとんど組めるようになったかなと感じています。

Release Preview 2の目玉の改善だったようで、このようにアピールされています。

[追記終わり]

FlutterでiOSネイティブアプリに見紛うようなUIを組むことは現時点では難しい

まず、現時点では、iOSネイティブアプリに見紛うようなUIを組むことは難しいとみなしています。Flutterは独自描画形式で、ネイティブUIっぽいものを組もうとした場合はそれを真似して作られた(悪く言えば偽物の) Cupertino (iOS-style) Widgets を使うことになるからです。

以下の図(Why I move to Flutter より)の上のOEM Widgetsがプラットフォームの提供しているUIコンポーネントですが、下のFlutterの図ではそれが欠けてそれぞれのプラットフォームのCanvas(iOSではUIView)上への独自描画になっています。

ネイティブアプリ
Flutter

また現時点ではそれらiOSネイティブUIを模したWidgetのクオリティ(再現度)はあまり高くなく量も十分では無いと感じました。Flutterは今はまだMaterial Components Widgets 開発やその他全体のクオリティ向上などに開発リソースが偏重していて、iOSっぽいUIへのケアはまだ軽視されている段階なためだと解釈しています。

そのため、現時点ではiOSネイティブアプリのようなUIを目指すには、クオリティが足りないと感じたものや足りないWidgetを自作する必要があります。そうなると、せっかくのFlutterの特徴である高い生産性が活きてこなくなって使うメリットがどんどん失われていってしまいます。

iOSアプリもマテリアルデザインで妥協するのが良さそう

現時点ではどうするのが良いかというと、個人的にはiOSネイティブアプリっぽいUIを目指すことは完全に諦めて、iOSでもマテリアルデザインに従うという妥協をするのが良いと思っています。今の段階で無理してiOSネイティブアプリっぽいUIを目指しても実装コストは嵩み、かつ似て非なる残念なものとなって、むしろマイナスの結果になる可能性が高いと思っています。また、例えばGoogle製のマテリアルデザインのiOSアプリは一般ユーザーにとって十分ウケが良いと思っていて(僕もまあまあしっくり来ています)、その方向性を目指すのが現時点でFlutterを使ってiOSアプリを作る際に得策かなと感じています。

あるいは、独自デザイン色が強いアプリ(Snapchat・Tik Tokなどのようなイメージ)の場合は、Flutterは自由なレイアウトを組みやすいのでかなり向いているはずです。マテリアルデザインに沿うとほぼ既製Widgetの組み合わせだけで小綺麗なUIを組めることに比べると独自UI実装はもちろん手間が増えますが、他の開発フレームワークと比較した場合として有利だと思っています。

テキスト入力周りが怪しい(らしい)

Flutterは基本的に独自描画で構成されていますが、ステータスバーなど一部はネイティブビューです。キーボードも同様で、テキスト入力中はキーボード部分はネイティブ、入力のハンドリング・描画はFlutterという構成になっています。

そのためか、テキスト入力周りに若干怪しさがあるようです。そのうち解消されるとは思いますが、このあたりはまだ注意が必要だと思っていて、きめ細かいテキスト入力ハンドリングが必要なアプリ(リッチテキスト編集アプリなど)をFlutterで作る際はこのあたりを入念に調査してからが良いと思っています。

以下の記事では、ネイティブ画面に逃して対処したとのことです。

テキスト入力欄の改行入力の動作が怪しいので、同様にプラットフォーム・ネイティブの画面へ遷移してテキスト入力

Android / iOS アプリの開発にクロスプラットフォームの Flutter を実戦投入した

ネイティブ機能をフル活用するのは現状難しいところがある

Flutterでネイティブ機能APIを利用する場合は、まずFlutter Packagesからすでに対応済みのものが無いか探します。

メジャーなネイティブAPIアクセスは一通りできるようになっていて、むしろネイティブコードより簡潔に書けて驚くこともあるくらいです。逆にマイナーなネイティブAPIが必要だったりきめ細かいハンドリングが必要だったりした時に既存のパッケージだけでは済まないことがまだけっこうあります。

iOS端末の時はiOSにしか無いAPIを利用したいことなどもあるはずですが、特にそういう目的に対応したパッケージはまだまだかなり手薄な印象です。

そういう時は、プラグインを自作すれば解決可能であるものの、もちろん相応の手間がかかります。プラグインをたくさん自作しないと作れなさそうなアプリの場合はFlutterはやめてネイティブアプリとして作った方が無難に思います。

Architectural overview: platform channels

逆に言うと、どうしてもまだパッケージ提供されていないネイティブAPIを使いたい時は自分でプラグイン自作をがんばれば大抵何とかなるということでもあります。

ネイティブAPIを扱う時は以下の前者のようにするものが多い(例えばFirebaseプラグインは大体そうなっている)ですが、例えばimage_pickerプラグインのようにネイティブビュー(iOSではUIImagePickerController)を表示してその結果を受け取るということもできます。

  • ネイティブAPIを呼んで結果を受け取ってそれを元にFlutterのビューで表示
  • ネイティブのビューに丸投げ

あと、App Extensions 対応がやや厳しい気がしますが、まだきちんと検証できていません。iOSネイティブ実装を組み合わせれば大体対応できそうな気がするものの、Dartで記述したロジックを流用できずネイティブコードとの二重実装になりそうなイメージです。

将来的にはiOSネイティブアプリっぽいUIの実現も可能かもしれない

将来的には、Cupertino (iOS-style) Widgets開発にもっと開発リソースが割かれて質・量ともに十分になってくる可能性もまあまああると思っています。FlutterはまだRelease Preview 1(正式リリース前)で、今後の期待値込みで考えるべきだと思っています。

しかし、仮に将来Cupertino (iOS-style) Widgetsの質・量が十分になってきたとしても、iOSネイティブアプリに見紛うようなUIを組めるようになるかはかなり微妙だと思っています。ネイティブUIの振る舞いを100%再現するのは難しい作業だからです。ただ、「iOSネイティブ開発者なら多少気になるけど一般ユーザーはほとんど違和感無い」程度のものは組めるようになるかもしれないとも思っています。もしそうなったら、マテリアルデザインで妥協するか、iOSネイティブアプリっぽいUIを目指すか、けっこう迷う気がします。この場合でも、前者にすると、Androidアプリとの分岐実装や確認の手間が省けるなどのメリットは大きいですね。

ネイティブUIの振る舞いを100%再現するのは難しい作業だからです。

ちなみに、FlutterによるAndroidアプリではこれは問題にならないのかというと、同じGoogleが開発しているという理由であまり苦労なくほぼ100%近い再現が可能だと思っています。

このあたりは、GoogleのiOSメインエンジニアの方が書かれた以下の記事でも触れられていて、とても同意できました。

Here is one of the downsides of Flutter: In my opinion, and when built for iOS, this facsimile is imperfect. The UI looks just a little off. The scroll physics aren’t quite right. Animations don’t move in quite the way I would expect. It’s climbing the cliff at the other side of the uncanny valley, but not quite out of it. I have less experience of Android, so find it hard to make a comparison there. But I’m told it does a much better job[4].

[4]. This isn’t a knock against either Android or Flutter itself. It stands to reason that a team within Google would have an easier time reproducing the Android look and feel than the iOS look and feel. Need to quantify the scroll physics used by Android? Just look at the code. That’s not really an option for iOS.

An iOS Developer’s Opinions of Flutter

Flutterをどう活用しようと思っているか

Androidアプリ開発

僕はAndroidネイティブアプリ開発スキルが無い(iOSアプリ開発への習熟度向上・サーバーサイドなど違う方面に学習リソースを充てていた)ので、FlutterでAndroidネイティブアプリに遜色無いものが作れそうというのが魅力的でした。Android開発者だと、Java・Kotlinでネイティブ開発かFlutterでの開発かでけっこう迷いそうな気がしていますが、僕の場合はAndroidネイティブ開発スキルがまだ無かったからこそFlutterに全振りしやすく感じています。

クロスプラットフォーム開発フレームワークを扱う上でもネイティブアプリ開発スキルは必須という論調がありますが、Flutterは独自描画方式なので基本的にはFlutterに習熟するだけで大丈夫という認識です。

iOSアプリエンジニアとしてFlutterでAndroidアプリ開発をするには、Flutter習得に加えて、以下のスキル程度で済むと思っています。

  • プロジェクト設定・ビルド周りの諸々
  • マテリアルデザイン
  • (できればAndroid端末を普段使いしてAndroidっぽいアプリに慣れ親しむ)
  • (プラグインを自作する場合はもちろんそのネイティブコードを書くだけのスキルは必要だが、既存ので済めば不要)

逆にAndroidアプリ開発者がiOSアプリをFlutterで作る場合は、同じくビルド周りと Human Interface Guidelines (iOSもマテリアルデザインベースにする場合不要かも)の理解程度で良いと思います。

ただ、ある程度の規模のアプリを作っているとネイティブ知識が無いと解決が難しいようなこともあり得る気もします。「Flutterではネイティブ開発スキルがあっても意味が無い」とまでは全く思っていませんし、むしろ逆にFlutterを良い機会に必要に応じてAndroidネイティブ開発に多少慣れ親しめると良いなと思っています。

クロスプラットフォーム開発

ここまで述べてきた通り、FlutterでiOSネイティブアプリに遜色の無いものを作るのは現状厳しいと思っているので、FlutterでiOSアプリも含めてクロスプラットフォーム開発するべきかはケースバイケースだと思っています。

ただ、1人でAndoird・iOSアプリの両開発する場合はリソースも限られるので、よほどFlutterとの相性が悪く無い限りはFlutterでiOSアプリも作る選択を取る気がします。

また、iOSアプリはネイティブで作る選択を取った場合、慣れればFlutterの方がサクサク作れるはずなので、FlutterによるAndroidファーストでiOSネイティブは後追い実装が良さそうと思っています。

デザインツール

iOSネイティブアプリ開発では、個人開発の場合でも頭の中によほどしっかりとデザインイメージが固まっていない限りは Sketch などのデザインツールを使って予めデザインを調整してから実装に取り組むべきと考えていて、そうしています。実装しながらデザイン調整すると細かい調整の度にリビルドが必要になったりして結局余計に時間がかかってしまうことが多いからです。

しかし、正直Sketchで秩序立ったデザイン管理をするのもけっこう大変で個人的にはけっこうだるい作業なので、Flutterで代用できないかな?と考えました。ただ、Flutterでは現状デザインプレビューが無いので後から見返したときに実行してその画面にたどり着く必要があって若干厳しい気もしました。また、やはりさすがにデザインツールよりレイアウト整えるコストが高いかなとも思いました(慣れればSketchでキレイに管理するコストとFlutterで書くコストが同等程度になるかも?とも思いつつ)。

ただ、Flutterではデザイン調整の試行錯誤コストが低いので、特に個人開発の場合は別途デザイン用意せずに直接実装で良い気はします。チーム開発では普通にSketchなどのデザインツール使わないとやはり厳しいとは思いました。

Flutterでは現状デザインプレビューが無い

[追記] 僕が知らなかっただけで、Experimentsな機能として対応済みだったことに気付きました。なかなか良い感じですが、まだ不安定です。また、デザインというよりレイアウトプレビューといった感じで、「デザインチェック」目的には今のところ使えないと思いました。

プロトタイピングツール

一方、プロトタイピングにはFlutterはかなり向いていると感じています。初めのFlutter習熟コストは決して低くはないですが、それを乗り越えればサクサクと何の制約も無く好きな画面・機能を作って試用することができます。

これについては公式のFAQでも触れています。

For designers, Flutter helps deliver the original design vision, without loss of fidelity or compromises. It also acts as a productive prototyping tool.

What does Flutter do?

最後に、

さんの書かれた Androidネイティブ開発者目線の同様な記事も紹介します💁‍♀️こちらの方が9ヶ月新しい内容になっています。

今後の記事の予定

今回は実際のコードがほとんど出てきませんでしたが、少しずつそういう記事も増やしていく予定です。今のところ、こういったものを予定しています。

  • Flutterの効率良い学び方 (書きました)
  • Scoped Model・BLoC(Business Logic Component)パターンなど、まだ体系的な説明が不足している事柄についての解説

[追記] 関連記事書きました。

--

--