- Flutter と Jetpack Compose は宣言型のリアクティブ UI モデルを共有していますが、言語、エコシステム、プラットフォームの範囲が異なります。
- Compose は、コンポーザブルをウィジェットに、遅延リストを ListView/GridView に、キャンバスを CustomPainter に、テーマを ThemeData に、Flutter の概念にきれいにマッピングします。
- Android ネイティブ スキル (ライフサイクル、ナビゲーション、リソース、同時実行) は、ウィジェット、ナビゲーター、アセット、async/await を通じて Flutter に直接転送されます。
- Android のみのプロジェクトには Compose が適しており、Android、iOS、ウェブ、デスクトップ用の単一のコードベースが必要な場合は Flutter が優れています。
すでに Jetpack Compose を使用して UI を記述することに慣れていて、Flutter に移行するのがどのくらい難しいのか疑問に思っている場合は、最適なタイミングです。 どちらのツールキットも宣言型でリアクティブであり、Googleによって構築されているため、メンタルモデルの大部分はほぼ1対1で引き継がれます。主な違いは、言語(Kotlin vs Dart)、プロジェクト構造、そして各フレームワークが基盤となるAndroid(Flutterの場合はiOS、ウェブ、デスクトップ)レイヤーとどのように通信するかにあります。
このガイドは、マーケティングの誇張なしに、Flutter を深く理解したい Jetpack Compose 開発者向けに特別に書かれています。 コアコンセプトが2つの世界の間でどのようにマッピングされているかを学びます。コンポーザブルとウィジェット、修飾子とコンストラクタパラメータ、遅延レイアウトとListView/GridView、CanvasとCustomPainter、Navigation ComposeとNavigator、rememberとStatefulWidgetなど、様々な要素が関係しています。また、Androidの幅広い知識(View、ライフサイクル、リソース、インテント、バックグラウンド処理)とFlutterの同等の知識を関連付けることで、学習曲線が登り坂ではなく、横滑りのように感じられるようになります。
Jetpack ComposeからFlutterへ:スキルが活かせる場所
Flutter は、Dart 言語を使用してクロスプラットフォーム アプリを構築するための Google の UI フレームワークです。一方、Jetpack Compose は、Kotlin を使用したネイティブ Android 向けの Google の最新 UI ツールキットです。 内部的には異なるランタイムをターゲットにしていますが、アーキテクチャ的には UI を状態の関数として記述し、フレームワークにいつどのように再描画するかを判断させるという、同じ大きな考え方を共有しています。
Jetpack Compose では、構成可能な関数、修飾子、再構成の観点から考えます。Flutter では、ウィジェット、コンストラクター パラメーター、再構築の観点から考えます。 名前が異なっていても、動作は驚くほど似ています。UI 要素のツリーを構築し、各ノードは不変であり、状態が変化するとフレームワークがそのツリーを再度調べて更新されたインターフェイスを生成します。
重要な違いの 1 つは、Flutter は設計上クロスプラットフォームであることです。 同じDartコードベースで、Android、iOS、ウェブ、Windows、macOS、Linuxをターゲットにできます。ComposeはAndroid以外にも拡張中です(例えばCompose Multiplatform)。しかし、Flutterのマルチデバイス対応は現時点ではるかに成熟し、統一性も高くなっています。だからこそ、多くのAndroidファーストチームがiOSやデスクトップへのリリースを検討する際に、Flutterに注目しているのです。
Android プラットフォーム自体の理解は、Flutter プロジェクトでも依然として非常に重要です。 UIレイヤーは純粋なDartとウィジェットですが、Flutterは権限、システム設定、プラットフォームAPI、通知、バックグラウンド処理など、プラグインやプラットフォームチャネルを介してアクセスする多くの機能をAndroid(およびiOS)に依存しています。つまり、Androidの動作についてこれまで培ってきた直感は無駄にならず、レイヤーを1つ下げるだけで済みます。
宣言型 UI モデル: コンポーザブル vs ウィジェット
Jetpack Compose と Flutter はどちらも宣言型 UI モデルを実装しています。つまり、ビューを段階的に変更する「方法」ではなく、特定の状態で UI がどのように見えるかを記述します。 ビューでセッターを呼び出す代わりに、状態が変わったときにツリーを再構築し、フレームワークが効率的に比較して再描画できるようにします。
Jetpack Composeでは、UI要素は、 @Composable多くの場合、 Modifier. ボタンは Button(onClick = ..., modifier = Modifier.padding(16.dp))修飾子チェーンは、基礎となる型を変更せずにコンポーザブルを装飾またはレイアウトし、Compose は再コンポジションを使用して、入力が変更されたツリーの部分のみを更新します。
Flutter では、UI 要素はウィジェット、つまり構成を記述する単純な Dart オブジェクトです。 これらも不変でツリー構造になっていますが、通常は修飾子を渡す代わりに、レイアウトやスタイルに関する引数をコンストラクタのパラメータで直接渡すか、ウィジェットを他のレイアウトウィジェットでラップします。例えば、次のように記述します。 Padding(padding: EdgeInsets.all(16), child: ElevatedButton(...)) 同様の結果を達成します。
コンポーザブルとウィジェットの両方のライフサイクルは意図的に短命かつ不変です。 ビューは、新しい入力によって置換が必要になるまでのみ存続します。ビュー自身の存続期間を管理したり、直接的に変化したりすることはありません。これは、ビューが長期間存続するオブジェクトであり、時間の経過とともに再利用され、変化するという従来のAndroid Viewの世界からの概念的な転換であり、FlutterにおいてComposeの考え方が非常に自然に感じられる理由です。
内部的には、両方のフレームワークのレイアウトは同じ親主導の制約ベースのパターンに従います。 親は自身のサイズを計測し、制約を下位に渡します。子はそれらの制約を考慮してサイズを選択し、親は子の位置を決定します。Flutterでは、これが次のように直接表示されます。 BoxConstraints; Composeでは、MeasurePolicy実装で処理されます。どちらの場合も、親ウィジェットは子ウィジェットを制限できます。ウィジェットは好きなサイズや位置を自由に選択することはできません。
アプリの構造化: エントリポイント、スキャフォールディング、レイアウト
AndroidのComposeでは、エントリポイントは通常 Activity (多くの場合、 ComponentActivity)に電話する setContent コンポーザブルをホストします。 そこから、通常は次のような構成可能なツリーを構築します。 MaterialTheme 高レベルのレイアウトを定義するサーフェスまたはスキャフォールド。
Flutterでは、エントリーポイントはDartです main 呼び出す関数 runApp アプリケーションのルート ウィジェットを使用します。 その根は一般的に MaterialApp or WidgetsApp ウィジェットはルーティング、テーマ設定、ローカリゼーション、そして基本ナビゲータを設定します。最初に表示する「画面」では、多くの場合 Scaffold ウィジェットは、 Scaffold Material 3 Compose では、アプリ バー、本体、フローティング アクション ボタン、引き出しなどが提供されます。
単純なテキストや静的コンテンツの場合、Compose はデフォルトでコンテンツを折り返し、サイズを本来のコンテンツに合わせますが、多くの Flutter ウィジェットは、制約がない限り、デフォルトでより多くの利用可能なスペースを占めます。 例えば、 Text 列内でコンポーザブルな場合、幅は自動的に埋められません。Flutterでは、 Text 内部 Column 親要素の制約に応じて動作が異なります。Flutterでコンテンツを中央に配置するには、多くの場合、要素を Center ウィジェット、または次のようなレイアウトウィジェットを使用します Align, Row, Column, Expanded 配置プロパティと組み合わせます。
リニアレイアウトはほぼ完璧にマッピングされます。Composeは Row および ColumnFlutter も同様です。 Flutterでは、子要素を List<Widget> 次のようなプロパティで間隔と配置を制御します。 MainAxisAlignment および CrossAxisAlignmentComposeでは、 horizontalArrangement, verticalArrangement, horizontalAlignment および verticalAlignment便利な考え方としては、「Arrangement」で終わるプロパティは Flutter の主軸にマップされ、「Alignment」で終わるプロパティは交差軸にマップされます。
相対的または重複するレイアウトが必要な場合も、アプローチは概念的に一致します。 Android XMLでは、 RelativeLayout または入れ子になった LinearLayout および FrameLayout. Composeでは、 Row, Column および Box (またはカスタムレイアウトを書く)。Flutterでは、アナログは Row, Column および Stack 配置された子要素と配置オプションを組み合わせることで、要素同士を相対的に配置するためのメンタルモデルは、ほぼ変化なく変化します。
ボタン、入力、インタラクション
Jetpack Composeでは、ボタンを作成するためには通常、 Button またはそのマテリアルバリアントの1つ。マテリアル3では、次のような特定の実装に解決されます。 FilledTonalButton. あなたは onClick ラムダとオプションのスタイル設定、多くの場合以下のようなパラメータ経由 colors または、パディング、幅、配置の修飾子。
Flutterでは、同様のことは次のようなウィジェットを使うことで実現できる。 FilledButton, ElevatedButton, TextButton or OutlinedButton. それぞれ onPressed コールバックと child ウィジェット—ほとんどの場合 Textを渡すことでカスタマイズできます style 、 ButtonStyle または、グローバル テーマ オーバーライドを使用すると、ボタン ファミリ全体の色、形状、高度、サイズを一元的に調整できます。
ジェスチャーを扱うために、Composeは次のような修飾子に依存しています。 Modifier.clickable 多くの場合、必要に応じて専用のジェスチャー検出器に切り替えることもできます。 長押し、ドラッグ、カスタム ジェスチャは通常、専用の修飾子 API とインタラクション ソースを通じて構成されます。
Flutterは明示的に GestureDetector ジェスチャーサポートが組み込まれていないものをラップするウィジェット。 幅広いコールバックを提供します: onTap, onDoubleTap, onLongPress, onVerticalDragStart, onVerticalDragUpdate, onHorizontalDragEnd などなど。ウィジェットは ElevatedButton すでに公開している onPressed プロパティですが、完全にカスタムのUI要素の場合は GestureDetector または、次のような高レベルウィジェット InkWell マテリアルリップルフィードバック用。
Flutterのテキスト入力は次のように管理されます。 TextField or TextFormField、そのスタイリングはComposeの TextField および OutlinedTextField コンポーザブル。 ヒント、ラベル、エラー、境界線を設定するには、 InputDecoration 使い方に似ている TextFieldDefaults または、Compose テキストフィールドのパラメータ。Compose と同様に、通常はビューを手動で操作するのではなく、状態を変更してデコレーションを再構築することで、エラーメッセージをリアクティブに表示します。
リスト、グリッド、スクロールコンテンツ
Jetpack Compose では、リストに対して 2 つの主な戦略を提供しています: シンプル Column/Row 小さなコレクションの反復処理と LazyColumn/LazyRow/LazyVerticalGrid/LazyHorizontalGrid 大規模なリストや動的なリストの場合。 遅延コンテナーは表示されているものだけを作成するため、何千ものアイテムを処理するときに高いパフォーマンスを維持できます。
Flutter は同じ「小さい vs 大きい」アプローチに従いますが、ウィジェットが異なります。 画面に収まる小さなリストの場合は、 Column データをマッピングする childrenスクロールするものには手を伸ばす ListView or GridView必要な場合にのみ子要素を遅延生成するビルダー コンストラクターを備えています。
Flutterの一般的なパターンは ListView.builderこれは、Compose の遅延リスト項目 DSL を反映しています。 あなたは itemCount と itemBuilder コールバック; Flutterは0からインデックスでそのビルダーを呼び出します itemCount - 1 新しいアイテムが表示されるたびに、ビルダー内では、シンプルなものから、ほぼすべてのウィジェットを返すことができます。 ListTile テキストとアイコンを使用して、複雑なカスタム リスト行を作成できます。
グリッドについては、Composeの LazyVerticalGrid および LazyHorizontalGrid Flutterのマップ GridView ウィジェット。 Flutterは列数を直接グリッドに渡す代わりに、次のようなデリゲートを使用することが多い。 SliverGridDelegateWithFixedCrossAxisCount or SliverGridDelegateWithMaxCrossAxisExtent セルのレイアウトを制御します。これらのデリゲートは、「列数」や「最大セル幅」といったルールをカプセル化しており、これはComposeで使用するグリッドサイズパラメータと似ています。
スクロール動作も両方のツールキットで同様です。 Composeの遅延リストにはスクロール機能が組み込まれているため、追加のスクロールコンテナで囲む必要はありません。Flutterでは、多くのリストウィジェットやグリッドウィジェット自体がスクロール可能ですが、繰り返しのない単一のコンテンツでスクロールする必要がある場合は、 SingleChildScrollViewスクロール可能なカスタム ページを構築するには、より高度なユース ケースに合わせてスライバーをネストまたは構成することになります。
適応性と応答性に優れたUIパターン
Composeは、カスタムレイアウト、 BoxWithConstraints, WindowSizeClass および Material 3 アダプティブ ライブラリ。 これらを使用すると、利用可能なスペース、姿勢、デバイスのカテゴリに基づいて構成を変更でき、プロジェクトの複雑さに応じてそれらを混在させることができます。
Flutter はこれらの API を直接ミラーリングしようとはしませんが、基本的な考え方は同じです。つまり、制約と画面の特性を検査し、レイアウトを分岐します。 2つの主なツールは LayoutBuilder および MediaQuery. LayoutBuilder パス BoxConstraints 下に移動すると、特定の幅または高さを超えるウィジェットを入れ替えたり並べ替えたりできるようになります。 MediaQuery 高レベルのブレークポイントの画面サイズ、向き、パディング、ピクセル密度を公開します。
Compose の適応型ソリューションと Flutter の適応型ソリューションを 1 対 1 でマッピングすることを目指すのではなく、設計要件の観点から考える方が効果的です。 UIがスマートフォン、タブレット、デスクトップでどのように適応すべきかがわかれば、そのロジックをComposeの WindowSizeClass 適応型レイアウトや、Flutterの制約駆動型とメディア駆動型の分岐など。同じ設計思考なのに、APIは異なる。
状態管理: remember と StatefulWidget の比較など
Jetpack Composeは一時的なUI状態を次のように保存します。 remember そして、国家保有者のような mutableStateOf、しばしばと組み合わせて ViewModel より長く存続する状態のためのアーキテクチャ コンポーネント。 状態が変化すると、再コンポジションが発生し、関連するコンポーザブルが新しい値を取得します。
Flutterの低レベル状態の話は StatefulWidget およびそれに関連する State オブジェクト。 状態を保持したいウィジェットを拡張して定義します StatefulWidget、別の State<MyWidget> 可変フィールドを格納するクラス。これらのフィールドを更新するたびに、 setState()は、ウィジェットツリーのその部分をダーティとしてマークし、再構築をトリガーします。このレベルでは、Composeの状態を次のように保存するのと非常に似ています。 remember 値が変更されたときにコンポーザブルを無効にします。
より複雑なアプリの場合、Flutter はコミュニティとファーストパーティのパターンに大きく依存します。 Provider、Riverpod、Bloc、Redux スタイルのストアなど。 これらはAndroidアーキテクチャスタックの類似物として機能します。ViewModel + LiveData/Flow + Composeプロジェクトのリポジトリです。ビジネスロジックを一元化し、ウィジェットの再構築を駆動するリアクティブなデータストリームを公開します。Composeの経験があれば、APIが異なっていても、これらのパターンの多くは馴染みのあるものに感じるでしょう。
Android 開発者がよく驚く点の 1 つは、Flutter のステートレス ウィジェットとステートフル ウィジェットの両方が頻繁に再構築され、アニメーション中のフレームごとに再構築される可能性があることです。 違いは再構築の頻度ではなく、変更可能な状態が保存される場所にあります。 StatefulWidget あなたに仲間を与える State 生き残ったオブジェクトは再構築されます。 remember Compose で値が再構成されても存続できるようにします。
描画、アニメーション、ビジュアルの磨き
Androidを直接操作したことがあるなら Canvas および Drawable、Composeの Canvas composable はおそらく簡単に感じられたでしょう。 Kotlin で図形、画像、テキストを描画するための宣言的な方法を提供し、従来のカスタム ビューの命令型の儀式の多くを隠します。
Flutterは同様の描画面を Canvas API経由でアクセス CustomPaint および CustomPainter. 実装する CustomPainter オーバーライドするクラス paint キャンバスに描画する方法 Paint オブジェクト、パス、変形などを設定します。そして、そのペインターを CustomPaint ウィジェット。Compose と Flutter はどちらも内部的には Skia エンジンに依存しているため、プリミティブ(線、パス、シェーダー)は Android の 2D レンダリングと非常によく似ています。
アニメーションに関しては、Flutterは明示的なアニメーションシステムに依存しています。 AnimationController, Animation<T> および Tween、さらに豊富なアニメーション ウィジェットのセット。 コントローラをインスタンス化します(通常は SingleTickerProviderStateMixin vsyncの場合)、0-1の進行状況をドメイン値にマッピングするCurvedAnimationsまたはTweenを定義し、それらを次のようなウィジェットに接続します。 FadeTransition, ScaleTransition, AnimatedBuilder または暗黙的なウィジェット AnimatedContainerアニメーションシステムでは、 AnimationStatus 開始、完了、または反転に反応するコールバック。
Jetpack ComposeのアニメーションAPIは上から下まで宣言型で、次のような関数があります。 animate*AsState、トランジション、アニメーションによる可視性など。 一般的なケースでは、コントローラーを手動で管理するのではなく、ターゲット状態を記述し、フレームワークが時間経過に応じて補間を行います。より高度な制御が必要な場合は、低レベルのプリミティブを使用できますが、通常のパスは従来のAndroid XMLや命令型のアニメーションコードよりも簡潔です。
概念的には、両方のツールキットを同じように使用します。ウィジェット/コンポーザブルを軽量かつ純粋に保ち、時間によって変化する値をそれらにプッシュし、フレームワークで補間と無効化を処理できるようにします。 Compose開発者として、Flutterの AnimationController 最初は少し古風に感じるかもしれませんが、タイミング、カーブ、オーケストレーションを非常に細かく制御できるようになります。
スタイル、テーマ、フォント、アセット
現代のアプリは洗練さで成否が決まるため、Flutter と Compose はどちらもテーマとスタイル設定に重点を置いています。 Composeは MaterialTheme カラー スキーム、タイポグラフィ、シェイプの定義が用意されており、テーマをネストしてサブツリーの値をオーバーライドできます (特定の領域に明るい表面や暗い表面を強制するなど)。
Flutterでは、同等のものは ThemeData に渡された MaterialApp or Theme ウィジェット。 基本色、明るさ、タイポグラフィ、コンポーネント固有のテーマを定義します。 elevatedButtonTheme, textButtonTheme, appBarTheme など。サブツリーをラップすることで、テーマをローカルでオーバーライドできます。 Theme 親ウィジェットをコピーし、特定のフィールドを調整するウィジェット。ライトモードとダークモードは、アプリレベルで切り替えることができます。 theme および darkTheme 制御する themeMode.
テキストのスタイリングはお馴染みの領域です。Composeでは、単純なプロパティを直接渡すか、 Text または供給する TextStyle オブジェクト。 Flutterはこれを反映して Text ウィジェットは TextStyle それを介して style パラメータに一致する最初のデバイスのリモートコントロール URL を返します。 TextStyle フォントファミリー、サイズ、太さ、文字間隔、行の高さ、装飾などをカバーします。グローバルテキストテーマは以下で定義できます。 ThemeData.textTheme そして、タイポグラフィを使うのと同じように、どこでも参照できます。 MaterialTheme Compose で。
フォントと画像はAndroidの従来の /res ディレクトリツリー。 Flutterは特定のフォルダレイアウトを強制しません。アセットは次のように宣言します。 pubspec.yaml そしてコードから参照します。画像は通常、 Image.asset()に基づいて正しい密度バケットを解決します。 devicePixelRatio論理ピクセルは、 dp Android では、物理的なピクセル密度を抽象化します。
カスタムフォントの場合、Compose ではフォントリソースをパッケージ化するか、Google Fonts などのプロバイダ経由で実行時に取得して、 FontFamily そしてタイポグラフィ。 Flutterはほぼ同じパターンを使用します。フォントファイルをアセットフォルダに配置し、 pubspec.yamlフォントファミリーを名前で参照するには、 TextStyle実行時に取得されるフォントが必要な場合は、人気の google_fonts フォント名にちなんで名付けられた Dart 関数を公開するプラグイン(例: GoogleFonts.robotoTextTheme()—テーマに素早く組み込むことができます。
どちらのエコシステムも文字列とローカリゼーションを第一級の問題として扱いますが、Flutter には Android の XML 文字列リソースに直接相当するものはありません。 代わりに、翻訳を .arb ファイルをFlutterローカリゼーションツールチェーンに接続します。その後、生成されたDartクラスを介してアクセスします。これは、 R.string Android コード内の識別子。
Flutter レンズを通して見る Android プラットフォームの概念
UI 以外では、Compose 開発者が抱える最大の疑問の 1 つは、Android の知識が Flutter のアーキテクチャにどのように対応するかということです。 幸いなことに、表面的な API が異なっていても、アクティビティ、ライフサイクル、インテント、バックグラウンド作業、リソース、ネットワークといったコアとなるアイデアの多くには、明確な対応物が存在します。
Androidでは、 Activity および Fragment 主な画面とコンテナです。Flutterではすべてがウィジェットであり、ナビゲーションは Navigator および Route オブジェクト。 ルートはアクティビティまたはフラグメントにほぼ相当しますが、通常はホスティングは1つだけです。 Activity Flutterエンジンを組み込んだAndroid上で動作します。Navigatorのスタックにルートをプッシュしたりポップしたりすることができます。 MaterialApp または直接構築 PageRoute 次のような例 MaterialPageRoute.
Androidのライフサイクルコールバック(onCreate, onStart, onResumeなど)はFlutterコードに1対1のフックがありませんが、アプリのライフサイクルを観察できます。 WidgetsBindingObserver. それは次のような状態を明らかにします resumed, inactive, paused および detachedこれはAndroidの表示、バックグラウンド、破棄の各フェーズにほぼ相当します。リソース管理のための低レベルのライフサイクルフックが本当に必要な場合は、通常、ネイティブAndroid側で実装します。 FlutterActivity または、Dart ではなくプラグインです。
Android では、インテントはアプリ内ナビゲーションとアプリ間通信という 2 つの役割を果たします。 前述の通り、FlutterにはインテントベースのナビゲーションAPIがありません。NavigatorはDartの世界ではそれを完全に置き換えます。アプリ間タスク(カメラの起動、ファイルピッカー、共有インテントの処理など)では、通常、必要なAndroid(およびiOS)の呼び出しをラップするプラグインを使用します。プラグインが存在しない場合は、MethodChannelsを使用して独自のプラグインを作成し、Dartとネイティブコード間で通信し、インテントと結果をメッセージとして転送することができます。
バックグラウンド作業とスレッドに関する理解も引き継がれますが、プリミティブは異なって見えます。 Androidでは、コルーチン、AsyncTask(レガシー)、WorkManager、JobScheduler、RxJavaなどを用いて、ネットワークとディスクのI/Oをメインスレッドから切り離すように促されます。一方、Dartはisolateごとにシングルスレッドのイベントループを使用し、I/Oにはasync/awaitを使用し、CPU負荷の高い処理には別のisolateを使用します。I/Oバウンドな処理については、関数に async, await 操作を実行し、イベント ループで UI の応答性を維持します。CPU 負荷の高いタスクの場合は分離を起動し、共有メモリではなくメッセージ パッシングを介して通信します。
ネットワーク面では、Flutterの人気は http このパッケージは、基本的な使用例では OkHttp + Retrofit と同様の役割を果たします。 低レベルのソケット処理の多くを隠蔽し、async/awaitと自然に統合します。複雑なニーズには、次のようなパッケージを利用できます。 dioしかし、基本的なパターンは変わりません。非同期呼び出しを行い、結果を待ち、 setState() または選択した状態マネージャーを使用して、影響を受けるウィジェットを再構築します。
プラグイン、ストレージ、Firebase、ツール
AndroidではGradleで依存関係を宣言するのが一般的ですが、Flutterでは次のように宣言します。 pubspec.yaml pub.dev から取得します。 Gradleファイルは android/ Flutter プロジェクトのフォルダーは、主にプラットフォーム固有の統合やカスタム ネイティブ ライブラリが必要な場合に使用され、日常的なアプリ開発は Dart の領域に留まります。
共有設定と SQLite にも、同等の機能が既成で用意されています。 Androidが提供するもの SharedPreferences 小さなキーバリューストレージにはSQLite(またはRoom)が、構造化データにはSQLite(またはRoom)が、Flutterはプラグインを介してこれらをラップします。 shared_preferences および sqfliteこれらのプラグインは Android と iOS の動作を統合するため、基盤となるネイティブ実装に依存しながら、プラットフォームに関係なく単一の Dart API を使用できます。
Firebase の統合も同様に簡単で最高クラスです。 Firebaseのほとんどのサービス(Authentication、Firestore、Realtime Database、Cloud Messaging、Analytics、Remote Configなど)には、FirebaseチームとFlutterチームによってメンテナンスされている公式Flutterプラグインがあります。これらのプラグインは、AndroidのFirebase SDKの概念モデルをミラーリングしていますが、Dart特有のAPIを使用しています。直接カバーされていないニッチなFirebase機能については、pub.devにサードパーティ製プラグインの健全なエコシステムがあります。
デバッグとプロファイリングのために、Flutter の DevTools スイートは、Android Studio のプロファイラーやレイアウト インスペクターに直接匹敵する豊富なツールボックスを提供します。 ウィジェットツリーの調査、リビルドの追跡、メモリ割り当ての監視、リークとフラグメンテーションの診断、Dartコードのステップ実行が可能です。Android StudioとVS CodeのIDEサポート、ホットリロードとホットリスタートと組み合わせることで、Flutter開発におけるフィードバックサイクルは、Composeで慣れ親しんだものと同等か、あるいはそれ以上にタイトに感じられます。
Androidのもう一つの一般的な懸念事項であるプッシュ通知は、Flutterでは次のようなプラグインを介して処理されます。 firebase_messaging. これらは内部的にはFirebase Cloud MessagingとAndroidおよびiOSのネイティブ通知フレームワークと通信しますが、アプリのロジックは統合されたDart APIで実行されます。設定とプラットフォーム固有の動作(Androidの通知チャンネルなど)は依然として重要であり、これらのプラットフォームの詳細に関する既存の経験は引き続き非常に重要です。
純粋に Flutter で実装することができない Android のホーム画面ウィジェットでも、Flutter コードと統合できます。 通常はJetpack GlanceまたはXMLレイアウトで構築し、次のようなパッケージを使用します。 home_widget Flutterアプリと通信し、データを共有し、ラスタライズされたFlutter UIをネイティブウィジェット内に画像として埋め込むこともできます。このハイブリッドなアプローチにより、プラットフォームの制約を尊重しながら、Flutterでの基本的なエクスペリエンスを維持できます。
これらすべての類似点を見ると、Jetpack Compose 開発者が Flutter に参入するのはまったくゼロから始めるわけではないことがわかります。 宣言型UI、Androidライフサイクル、ナビゲーション、状態、リソース、非同期処理に関する理解は、Flutterの世界に非常に自然にマッピングされます。最も大きく異なるのは、名前、言語(Dart)、そしてマルチプラットフォームの考え方です。ウィジェットとNavigatorを基礎概念として理解すれば、スタックの残りの部分はすぐに理解できるようになります。