跳至主要內容

將 Flutter 畫面新增至 Android 應用程式

本指南說明如何將單一 Flutter 畫面新增至現有的 Android 應用程式。Flutter 畫面可以新增為一般、不透明的畫面,或新增為透視的半透明畫面。本指南將說明這兩種選項。

新增一般的 Flutter 畫面

#

Add Flutter Screen Header

步驟 1:將 FlutterActivity 新增至 AndroidManifest.xml

#

Flutter 提供 FlutterActivity,以在 Android 應用程式中顯示 Flutter 體驗。如同任何其他的 ActivityFlutterActivity 必須在您的 AndroidManifest.xml 中註冊。將下列 XML 新增至您 AndroidManifest.xml 檔案中 application 標籤下方

xml
<activity
  android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@style/LaunchTheme"
  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  />

@style/LaunchTheme 的參考可以用任何您想要套用至 FlutterActivity 的 Android 主題來取代。主題的選擇會決定套用至 Android 系統 chrome(例如 Android 的導覽列)的色彩,以及 FlutterActivity 在 Flutter UI 首次自行呈現之前的背景顏色。

步驟 2:啟動 FlutterActivity

#

在您的 manifest 檔案中註冊 FlutterActivity 之後,新增程式碼以從您應用程式中任何想要的位置啟動 FlutterActivity。下列範例顯示從 OnClickListener 啟動的 FlutterActivity

ExistingActivity.kt
kotlin
MyButton(onClick = {
    startActivity(
        FlutterActivity.createDefaultIntent(this)
    )
})

@Composable
fun MyButton(onClick: () -> Unit) {
    Button(onClick = onClick) {
        Text("Launch Flutter!")
    }
}
ExistingActivity.kt
kotlin
myButton.setOnClickListener {
  startActivity(
    FlutterActivity.createDefaultIntent(this)
  )
}
ExistingActivity.java
java
myButton.setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    startActivity(
      FlutterActivity.createDefaultIntent(currentActivity)
    );
  }
});

先前的範例假設您的 Dart 進入點名為 main(),而且您的初始 Flutter 路由為 '/'。Dart 進入點無法使用 Intent 變更,但是初始路由可以使用 Intent 變更。下列範例示範如何啟動 FlutterActivity,使其在 Flutter 中初始呈現自訂路由。

ExistingActivity.kt
kotlin
MyButton(onClick = {
  startActivity(
    FlutterActivity
      .withNewEngine()
      .initialRoute("/my_route")
      .build(this)
  )
})

@Composable
fun MyButton(onClick: () -> Unit) {
    Button(onClick = onClick) {
        Text("Launch Flutter!")
    }
}
ExistingActivity.kt
kotlin
myButton.setOnClickListener {
  startActivity(
    FlutterActivity
      .withNewEngine()
      .initialRoute("/my_route")
      .build(this)
  )
}
ExistingActivity.java
java
myButton.addOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    startActivity(
      FlutterActivity
        .withNewEngine()
        .initialRoute("/my_route")
        .build(currentActivity)
      );
  }
});

"/my_route" 取代為您想要的初始路由。

使用 withNewEngine() 工廠方法會設定一個 FlutterActivity,其內部會建立自己的 FlutterEngine 執行個體。這會造成不少的初始化時間。替代方法是指示 FlutterActivity 使用預先暖機的快取 FlutterEngine,以盡量縮短 Flutter 的初始化時間。接下來將討論該方法。

步驟 3:(選用)使用快取的 FlutterEngine

#

每個 FlutterActivity 預設都會建立自己的 FlutterEngine。每個 FlutterEngine 都有不少的暖機時間。這表示啟動標準的 FlutterActivity 時,會在您的 Flutter 體驗顯示之前有短暫的延遲。為了盡量縮短此延遲,您可以在到達您的 FlutterActivity 之前暖機 FlutterEngine,然後改為使用您預先暖機的 FlutterEngine

若要預先暖機 FlutterEngine,請在您的應用程式中尋找合理的位置來建立 FlutterEngine 的執行個體。下列範例在 Application 類別中任意預先暖機 FlutterEngine

MyApplication.kt
kotlin
class MyApplication : Application() {
  lateinit var flutterEngine : FlutterEngine

  override fun onCreate() {
    super.onCreate()

    // Instantiate a FlutterEngine.
    flutterEngine = FlutterEngine(this)

    // Start executing Dart code to pre-warm the FlutterEngine.
    flutterEngine.dartExecutor.executeDartEntrypoint(
      DartExecutor.DartEntrypoint.createDefault()
    )

    // Cache the FlutterEngine to be used by FlutterActivity.
    FlutterEngineCache
      .getInstance()
      .put("my_engine_id", flutterEngine)
  }
}
MyApplication.java
java
public class MyApplication extends Application {
  public FlutterEngine flutterEngine;
  
  @Override
  public void onCreate() {
    super.onCreate();
    // Instantiate a FlutterEngine.
    flutterEngine = new FlutterEngine(this);

    // Start executing Dart code to pre-warm the FlutterEngine.
    flutterEngine.getDartExecutor().executeDartEntrypoint(
      DartEntrypoint.createDefault()
    );

    // Cache the FlutterEngine to be used by FlutterActivity.
    FlutterEngineCache
      .getInstance()
      .put("my_engine_id", flutterEngine);
  }
}

傳遞至 FlutterEngineCache 的 ID 可以是您想要的任何值。請確定您將相同的 ID 傳遞至任何應該使用快取 FlutterEngineFlutterActivityFlutterFragment。接下來將討論搭配快取 FlutterEngine 使用 FlutterActivity 的情況。

使用預先暖機的快取 FlutterEngine,您現在需要指示您的 FlutterActivity 使用快取的 FlutterEngine,而不是建立新的。若要完成此作業,請使用 FlutterActivitywithCachedEngine() 建構器

ExistingActivity.kt
kotlin
myButton.setOnClickListener {
  startActivity(
    FlutterActivity
      .withCachedEngine("my_engine_id")
      .build(this)
  )
}
ExistingActivity.java
java
myButton.addOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    startActivity(
      FlutterActivity
        .withCachedEngine("my_engine_id")
        .build(currentActivity)
      );
  }
});

使用 withCachedEngine() 工廠方法時,請傳遞在快取所需的 FlutterEngine 時使用的相同 ID。

現在,當您啟動 FlutterActivity 時,顯示 Flutter 內容的延遲會大幅減少。

具有快取引擎的初始路由

#

當使用新的 FlutterEngine 設定 FlutterActivityFlutterFragment 時,可以使用初始路由的概念。但是,當使用快取引擎時,FlutterActivityFlutterFragment 不提供初始路由的概念。這是因為快取引擎預期已在執行 Dart 程式碼,這表示設定初始路由的時間太晚。

想要讓快取引擎以自訂初始路由開始的開發人員,可以在執行 Dart 進入點之前,設定其快取的 FlutterEngine 以使用自訂初始路由。下列範例示範如何搭配快取引擎使用初始路由

MyApplication.kt
kotlin
class MyApplication : Application() {
  lateinit var flutterEngine : FlutterEngine
  override fun onCreate() {
    super.onCreate()
    // Instantiate a FlutterEngine.
    flutterEngine = FlutterEngine(this)
    // Configure an initial route.
    flutterEngine.navigationChannel.setInitialRoute("your/route/here");
    // Start executing Dart code to pre-warm the FlutterEngine.
    flutterEngine.dartExecutor.executeDartEntrypoint(
      DartExecutor.DartEntrypoint.createDefault()
    )
    // Cache the FlutterEngine to be used by FlutterActivity or FlutterFragment.
    FlutterEngineCache
      .getInstance()
      .put("my_engine_id", flutterEngine)
  }
}
MyApplication.java
java
public class MyApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // Instantiate a FlutterEngine.
    flutterEngine = new FlutterEngine(this);
    // Configure an initial route.
    flutterEngine.getNavigationChannel().setInitialRoute("your/route/here");
    // Start executing Dart code to pre-warm the FlutterEngine.
    flutterEngine.getDartExecutor().executeDartEntrypoint(
      DartEntrypoint.createDefault()
    );
    // Cache the FlutterEngine to be used by FlutterActivity or FlutterFragment.
    FlutterEngineCache
      .getInstance()
      .put("my_engine_id", flutterEngine);
  }
}

藉由設定導覽通道的初始路由,相關聯的 FlutterEngine 會在初始執行 runApp() Dart 函式時顯示所需的路由。

在初始執行 runApp() 之後變更導覽通道的初始路由屬性不會有任何效果。想要在不同的 ActivityFragment 之間使用相同的 FlutterEngine,並在這些顯示之間切換路由的開發人員,需要設定方法通道,並明確指示其 Dart 程式碼變更 Navigator 路由。

新增一個半透明的 Flutter 畫面

#

Add Flutter Screen With Translucency Header

大部分全螢幕 Flutter 體驗都是不透明的。但是,有些應用程式想要部署看起來像強制回應視窗的 Flutter 畫面,例如對話方塊或底頁。Flutter 支援開箱即用的半透明 FlutterActivity

若要讓您的 FlutterActivity 半透明,請對建立和啟動 FlutterActivity 的一般程序進行下列變更。

步驟 1:使用具有半透明效果的主題

#

Android 需要針對使用半透明背景轉譯的 Activity 使用特殊主題屬性。建立或更新具有下列屬性的 Android 主題

xml
<style name="MyTheme" parent="@style/MyParentTheme">
  <item name="android:windowIsTranslucent">true</item>
</style>

然後,將半透明主題套用至您的 FlutterActivity

xml
<activity
  android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@style/MyTheme"
  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  />

您的 FlutterActivity 現在支援半透明。接下來,您需要啟動您的 FlutterActivity,並明確支援透明度。

步驟 2:以透明度啟動 FlutterActivity

#

若要使用透明背景啟動您的 FlutterActivity,請將適當的 BackgroundMode 傳遞至 IntentBuilder

ExistingActivity.kt
kotlin
// Using a new FlutterEngine.
startActivity(
  FlutterActivity
    .withNewEngine()
    .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
    .build(this)
);

// Using a cached FlutterEngine.
startActivity(
  FlutterActivity
    .withCachedEngine("my_engine_id")
    .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
    .build(this)
);
ExistingActivity.java
java
// Using a new FlutterEngine.
startActivity(
  FlutterActivity
    .withNewEngine()
    .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
    .build(context)
);

// Using a cached FlutterEngine.
startActivity(
  FlutterActivity
    .withCachedEngine("my_engine_id")
    .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
    .build(context)
);

您現在具有透明背景的 FlutterActivity