【Flutter】Flutter画面をフラグメント画面としてAndroidアプリに追加

# はじめに

Flutterのアプリをモジュール化してネイティブアプリに取り込むことで、Flutter画面をネイティブアプリ内で表示させることができます。(Add-to-app)
今回はAndroidアプリのFragmentとしてFlutter画面を表示させる方法について書いていきたいと思います。
一部分のコードを載せているので、詳細は以下のサンプルアプリを参照してください。

※ Activityとして表示させる方法は別記事に記載済

サンプルアプリ

https://github.com/w2406/native_android_app_with_flutter_fragment

# Flutterモジュール作成

以下のコマンドでネイティブアプリに追加するFlutterプロジェクトとaarモジュールを作成します。

```dart
flutter create -t module flutter_module
```

```dart
flutter build aar
```

# Androidアプリにモジュールを取り込む

settings.gradle.ktsとbuild.gradle.ktsに以下を追加して、Flutterモジュールとしてaarを取り込みます。

```dart
settings.gradle.kts

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        // 追加
        maven("https://storage.googleapis.com/download.flutter.io")
        maven(url = "../flutter_module/build/host/outputs/repo")
    }
}
```

```dart
build.gradle.kts

dependencies {
    // 追加
    debugImplementation(libs.flutter.debug)
    releaseImplementation(libs.flutter.release)
}

```

# 【Android】Fragmentを表示する場所を追加する

レイアウト(XML)にFragmentを表示する場所を追加します。
今回はactivity_main.xmlに追加しています。

```dart
<FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
```

# 【Android】FragmentとしてFlutter画面を呼び出す

`FlutterFragment` を継承したFragmentクラスを作成します。(一旦処理をまとめるために作成したけどいらないかも)

Fragmentクラスのインスタンスを生成もしくはすでに `FragmentManager` にあればそれを保持します。

```dart

FragmentManager fragmentManager = getSupportFragmentManager();
// 追加済みのフラグメントを探す
// フラグメントが存在していない場合は新規作成
FlutterFragment fragment = (FlutterFragment) fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT);
FlutterFragment flutterFragment = (fragment == null) ? FlutterSecondFragment.withCachedEngine(FLUTTER_ENGINE_ID).build() : fragment;

```

以下のようにしてFragmentを表示する場所のIDを指定して、Flutterの画面をFragmentとして表示させます。

```dart
getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragment_container, fragment, tag)
                .addToBackStack(null) // 戻るボタン対応
                .commit();
```

# (任意)メソッドチャンネルを追加する

FlutterEngineにメソッドチャンネルを紐づけて追加します。
その後にFlutterEngineをキャッシュして使用します。
キャッシュしたFlutterEngineをFlutterのFragment生成時に使用します。
これにより、Flutter画面からネイティブのコード呼ぶことができます。
(FlutterEngineキャッシュ&メソッドチャンネル追加はもっといい実装方法ありそう)

```dart
// メソッドチャンネルを追加する用のメソッド
public static void setMethodChannel(FlutterEngine flutterEngine) {
        new MethodChannel(
                flutterEngine.getDartExecutor().getBinaryMessenger(),
                CHANNEL
        ).setMethodCallHandler(
                (call, result) -> {
                    // Flutterから呼ばれるメソッド
                    if (call.method.equals("hello")) {
                        result.success("Hello from Android!");
                    } else {
                        result.notImplemented();
                    }
                }
        );
  }
  
// FlutterEngineの初期化してFlutterEngineをキャッシュに保存
flutterEngine = new FlutterEngine(this);
flutterEngine.getNavigationChannel().setInitialRoute("/");
flutterEngine.getDartExecutor().executeDartEntrypoint(
        DartExecutor.DartEntrypoint.createDefault()
);

// メソッドチャンネルを追加
FlutterSecondFragment.setMethodChannel(flutterEngine);

FlutterEngineCache
        .getInstance()
        .put(FLUTTER_ENGINE_ID, flutterEngine);
```

| androidのFragment | flutterのFragment |
| ---- | ---- |
| ![スクリーンショット 2025-05-11 16.32.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868196/1fd1ad27-4e8f-4c98-a88b-54b756e9acbf.png)| ![スクリーンショット 2025-05-11 16.32.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868196/8aed8f39-05c9-4c7b-a61a-cc35edfb5a9f.png) |

# おわり

今回はFlutter画面をAndroidのFragmentとして表示させました。
色々Add-to-appの課題もあると思うので、それらも調べてまとめていきたいと思います。