Flutter フレームワークに触れて
Flutter は Google が開発・メンテナンスしているオープンソースのモバイルアプリ開発フレームワークです。Flutter は Dart 言語で記述され、効率的なレンダリングエンジン、豊富なコンポーネントライブラリ、そして高速な開発サイクルを備えており、高品質でクロスプラットフォームなモバイルアプリケーションの構築に利用できます。
なぜクロスプラットフォームの選択肢に注目するのか
モバイル開発をしていると避けられない現実的な問題があります。同じプロダクトで Android と iOS の両方をカバーするということは、多くの場合 2 つのコードベース、2 つの技術スタック、2 倍のメンテナンスコストを意味します。かつて流行したハイブリッド方式は、WebView をラップするタイプだとパフォーマンスと体験に明らかな劣化があり、React Native のように JS コンポーネントをプラットフォームのネイティブコントロールにマッピングするタイプだと、クロスプラットフォームの一貫性が今一歩というところでした。
Flutter は別の道を選びました。プラットフォームのネイティブコントロールに依存せず、UI を完全に自前で描画するのです。これにより「1 つのコードベースで、全プラットフォームで一貫した表示」を先達よりも徹底して実現しており、私が時間をかけて触ってみようと思った理由でもあります。
レンダリングエンジン
Flutter のレンダリングエンジンは Skia グラフィックスライブラリを採用しており、高品質・高パフォーマンスな描画とアニメーション効果を実現できます。Flutter のコンポーネントライブラリには豊富な UI コンポーネントが含まれ、さまざまなスタイルのアプリケーションを手軽に作成でき、カスタムコンポーネントの開発もサポートしています。さらに Flutter は豊富な API とツールを提供しており、高速な開発サイクルと効率的なデバッグを支えています。
ここで自前描画の意味を少し掘り下げておきましょう。Flutter はインターフェースを各プラットフォームのネイティブコントロールに翻訳するのではなく、Skia を通じてキャンバス上にすべてのピクセルを直接描画します。プラットフォーム側は描画可能な Surface とイベント入力を提供するだけでよく、残りのレイアウト・描画・アニメーションはすべて Flutter エンジン自身が完結させます。利点は、同じ UI コードが異なる OS や OS バージョン上でも極めて一貫した描画結果になることです。特定のプラットフォームのコントロールの挙動の違いによって差異が生じることがありません。
クロスプラットフォーム能力
Flutter のクロスプラットフォーム特性も最大の強みの一つです。Android と iOS のアプリケーションを同時に開発でき、開発したアプリケーションは異なるプラットフォーム上でも同じユーザー体験を実現できます。さらに Flutter は Web やデスクトップアプリケーションの開発もサポートしており、さまざまなユースケースにソリューションを提供できます。
つまり、1 つのコードベースで理論上は Android、iOS、Web、そして Windows や macOS といったデスクトップまでカバーできるということです。もちろんターゲットプラットフォームごとの成熟度は同じではなく、モバイルが Flutter の最初に磨き上げられた主戦場です。しかしツール系や表示系のアプリであれば、マルチプラットフォーム再利用によるコスト削減は実際に効いてきます。
Dart 言語
Flutter は開発言語として Dart を採用しています。Dart はオブジェクト指向で静的型付けの言語であり、強力な型推論と非同期プログラミングのサポートを備え、開発効率とコード品質を高めることができます。Flutter の Dart コンパイラは Dart コードをネイティブコードにコンパイルし、さまざまなプラットフォーム上で高パフォーマンスかつ高速なレンダリングを実現できます。
Dart は Flutter にとって単なる「なんとなく選んだ言語」ではありません。JIT と AOT の 2 つのコンパイルモードを両方サポートしており、開発段階では JIT でコードの変更が即座に反映され、ホットリロードを支えています。リリース段階では AOT でマシンコードにコンパイルされ、実行時にインタプリタが不要で、パフォーマンスはネイティブに迫ります。1 つの言語で開発効率と実行パフォーマンスという 2 つの要求を同時に満たすのは、クロスプラットフォームフレームワークでは決して多くありません。
Java や JavaScript に慣れた人なら Dart の習得にほとんど障壁はありません。構文のスタイルは両者の中間で、async/await による非同期の書き方も直感的です。
Widget コンポーネントモデル
Flutter の UI フレームワークは「Widget」と呼ばれるコンポーネントモデルを採用しています。Widget は Flutter における最も基本的な構成要素で、UI 要素とロジックを含みます。Flutter のすべての UI 要素は Widget であり、テキスト、画像、ボタンなどが含まれます。Flutter の Widget は階層構造を持ち、ネストや組み合わせが可能で、複雑な UI インターフェースを自由に作成できます。
「すべては Widget である」というのが Flutter の中核的な設計哲学です。ボタンやテキストが Widget であるだけでなく、パディング(Padding)、中央揃え(Center)、ジェスチャー認識(GestureDetector)といった「振る舞い」までもが Widget です。複雑なインターフェースは巨大な基底クラスの継承によって実現するのではなく、小さな Widget を何層にも組み合わせることで実現します。「継承よりコンポジション」がここでは存分に体現されています。
Widget は可変状態を持つかどうかで 2 種類に分かれます。StatelessWidget は変化しない UI を記述し、StatefulWidget は State オブジェクトと組み合わせて変化する部分を管理します。状態が変わると、フレームワークが対応する Widget サブツリーを自動的に再構築します。この点を理解すれば、Flutter の宣言的 UI の考え方は基本的に腑に落ちるはずです。
ホットリロード
Flutter のホットリロード機能は、開発中に UI の変化をリアルタイムでプレビューでき、アプリケーションの再コンパイルや再デプロイが不要なため、開発効率とフィードバックの速さを大幅に高めます。さらに Flutter は豊富なデバッグツールと可視化ツールを提供しており、開発者が問題をすばやく特定して解決するのを助けてくれます。
ホットリロードの原理は、変更後のソースコードを実行中の Dart 仮想マシンに増分注入し、Widget ツリーを再構築するというものです。アプリケーションの現在の状態は保持されます。つまり深い階層のページのスタイルを調整するとき、毎回トップページからクリックして辿り直す必要はなく、変更して保存すれば画面が直接更新されます。UI 調整の体験は、ネイティブ開発と比べて質的な向上と言えます。
ハマりどころと注意点
触り始める前に知っておくと良い点がいくつかあります。
1)中国国内のネットワーク環境では、SDK のダウンロードや pub の依存関係の取得が非常に遅い、あるいは失敗することがあります。国内ミラーの設定(環境変数 PUB_HOSTED_URL と FLUTTER_STORAGE_BASE_URL の設定)が必要です。
2)Widget のネストが深くなるとコードの可読性が目に見えて低下します。1 つの build メソッドに数百行を積み上げるのではなく、早めに小さな Widget へ分割する習慣をつけることをおすすめします。
3)プラットフォームのネイティブ機能(Bluetooth、プッシュ通知など)を扱う場合は、Platform Channel を通じてネイティブコードと通信する必要があり、この部分では依然としてある程度の Android/iOS ネイティブの知識が求められます。
4)ホットリロードは万能ではありません。変更がグローバルな状態の初期化、main メソッド、enum などに及ぶ場合は、ホットリスタート(hot restart)や完全な再コンパイルが必要になります。
初めて flutter doctor を実行したときは、指示に従って環境の不足項目を一つずつ埋めておきましょう。後々の原因不明なビルドエラーを大量に省けます。
まとめ
Flutter フレームワークは実に良くできていると感じました。優れたコンポーネントが提供されており、Dart 言語との組み合わせで開発の入門は非常に速く進みます。いくつかデモを書いただけで、もう本格的なアプリ開発に入れる状態になりました。1 つのコードベースで Android、iOS、Windows デスクトップアプリ、Mac のすべてで動きます。自前描画のレンダリングがマルチプラットフォームでの一貫性を保証し、Widget を組み合わせる書き方は明快で直感的、ホットリロードのおかげで UI 調整も苦になりません。クロスプラットフォーム開発を試してみたい人にとって、Flutter は本気で取り組む価値のある選択肢です。
COMMENTS