2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AndroidアプリにFlutterをadd-to-appして複数の画面を扱う

Posted at

はじめに

この記事はFlutter公式( https://flutter.dev/docs/development/add-to-app/multiple-flutters )に載っているMultiple Flutter screens or viewsを試してみた記事になります。
今までadd-to-appは

  • 最初の画面を起動するのに時間がかかる(のでFlutterEngineのキャッシュが必要だった)
  • 1画面だけ扱うことを想定している(複数の画面を扱うのは無理では無いがトリッキーな方法が必要だった)
  • メモリを食う

などの課題がありました。
特に1画面しか扱うことを想定していないという制限は大きく、プロダクションでは実質使えない状態でした。
Flutter2.0のリリースに伴い実装されたFlutterEngineGroupを使うことでこれらを解決できます!

前提・環境

実装

FlutterEngineGroupの宣言

Applicationクラスを拡張してFlutterEngineGroupを宣言します

App.kt
class App : Application() {
    lateinit var engines: FlutterEngineGroup

    override fun onCreate() {
        super.onCreate()
        engines = FlutterEngineGroup(this)
    }
}

遷移処理の準備

EngineBindingsクラスを用意します

EngineBindings.kt
package com.example.addtoapptest

import android.app.Activity
import io.flutter.FlutterInjector
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.plugin.common.MethodChannel

interface EngineBindingsDelegate {
    fun onNext()
}

class EngineBindings(activity: Activity, delegate: EngineBindingsDelegate, entrypoint: String) {
    val channel: MethodChannel
    val engine: FlutterEngine
    val delegate: EngineBindingsDelegate

    init {
        val app = activity.applicationContext as App
        // This has to be lazy to avoid creation before the FlutterEngineGroup.
        val dartEntrypoint =
            DartExecutor.DartEntrypoint(
                FlutterInjector.instance().flutterLoader().findAppBundlePath(), entrypoint
            )
        engine = app.engines.createAndRunEngine(activity, dartEntrypoint)
        this.delegate = delegate
        channel = MethodChannel(engine.dartExecutor.binaryMessenger, "multiple-flutters")
    }

    fun attach() {
        channel.setMethodCallHandler { call, result ->
        }
    }

    fun detach() {
        // TODO: Uncomment after https://github.com/flutter/engine/pull/24644 is on stable.
        // engine.destroy();
        channel.setMethodCallHandler(null)
    }
}

Flutter用のActivityの用意

FlutterActivityと上記で宣言したEngineBindingsを継承したActivityを作成します。
entrypoint = ""が呼び出す画面の関数名になりますので、ここはdart側に合わせて適宜変更してください。

SingleFlutterActivity.kt
package com.example.addtoapptest

import android.content.Context
import android.content.Intent
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine

class SingleFlutterActivity : FlutterActivity(), EngineBindingsDelegate {
    private val engineBindings: EngineBindings by lazy {
        EngineBindings(activity = this, delegate = this, entrypoint = "firstScreen")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        engineBindings.attach()
    }

    override fun onDestroy() {
        super.onDestroy()
        engineBindings.detach()
    }

    override fun provideFlutterEngine(context: Context): FlutterEngine? {
        return engineBindings.engine
    }

    override fun onNext() {
        val flutterIntent = Intent(this, MainActivity::class.java)
        startActivity(flutterIntent)
    }
}

dart側の準備

main.dartに@pragma('vm:entry-point')で新しいエントリポイントを記述します。
ここで宣言した関数名とkotlin側で呼び出すエントリポイントを一致させましょう。

main.dart
import 'package:flutter/material.dart';

// MyAppの内容は省略しています
@pragma('vm:entry-point')
void firstScreen() => runApp(MyApp());

void main() => runApp(MyApp());

以上です。AndroidManifestにActivityに登録するのを忘れずに!

補足

  • FlutterEngineGroupはまだまだ実験的な機能とアナウンスされているので、実装はすぐ変わるかもしれません。
  • 実験的な機能であるためか、FlutterEngineGroupクラスではプロダクションで使わないでくださいというコメントがあります。導入の際は自己責任で!( https://api.flutter.dev/javadoc/io/flutter/embedding/engine/FlutterEngineGroup.html
  • @pragma('vm:entry_point')でも特にエラーが出ない上、なぜかデバッグビルドだと動いてリリースビルドだと動かないという不思議な動作をしました。アンダーバーではなくハイフンなのでご注意を!
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?