向 Android 應用新增 Flutter 螢幕
瞭解如何向現有的 Android 應用新增單個 Flutter 螢幕。
本指南介紹瞭如何向現有的 Android 應用新增單個 Flutter 螢幕。可以將 Flutter 螢幕新增為常規的不透明螢幕,或新增為可透視的半透明螢幕。本指南將介紹這兩種選項。
新增普通的 Flutter 螢幕
#
第 1 步:將 FlutterActivity 新增到 AndroidManifest.xml
#Flutter 提供了 FlutterActivity 以便在 Android 應用中展示 Flutter 體驗。與其他任何 Activity 一樣,FlutterActivity 必須在 AndroidManifest.xml 中進行註冊。請將以下 XML 新增到 AndroidManifest.xml 檔案的 application 標籤內:
<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 系統介面(如 Android 導航欄)的顏色,以及 Flutter UI 首次渲染前 FlutterActivity 的背景顏色。
第 2 步:啟動 FlutterActivity
#在清單檔案中註冊 FlutterActivity 後,在應用中您希望的位置新增程式碼以啟動 FlutterActivity。以下示例展示瞭如何從 OnClickListener 中啟動 FlutterActivity。
MyButton(onClick = {
startActivity(
FlutterActivity.createDefaultIntent(this)
)
})
@Composable
fun MyButton(onClick: () -> Unit) {
Button(onClick = onClick) {
Text("Launch Flutter!")
}
}
myButton.setOnClickListener {
startActivity(
FlutterActivity.createDefaultIntent(this)
)
}
myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity.createDefaultIntent(currentActivity)
);
}
});
上述示例假設您的 Dart 入口點名為 main(),且初始的 Flutter 路由為 '/'。Dart 入口點無法透過 Intent 更改,但初始路由可以透過 Intent 更改。以下示例演示瞭如何啟動一個在 Flutter 中初始渲染自定義路由的 FlutterActivity。
MyButton(onClick = {
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/my_route")
.build(this)
)
})
@Composable
fun MyButton(onClick: () -> Unit) {
Button(onClick = onClick) {
Text("Launch Flutter!")
}
}
myButton.setOnClickListener {
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/my_route")
.build(this)
)
}
myButton.addOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/my_route")
.build(currentActivity)
);
}
});
將 "/my_route" 替換為您所需的初始路由。
使用 withNewEngine() 工廠方法會配置一個內部建立其自己的 FlutterEngine 例項的 FlutterActivity。這會有一定的初始化耗時。另一種方法是讓 FlutterActivity 使用預熱後的快取 FlutterEngine,這可以縮短 Flutter 的初始化時間。接下來將討論該方法。
第 3 步:(可選)使用已快取的 FlutterEngine
#預設情況下,每個 FlutterActivity 都會建立自己的 FlutterEngine。每個 FlutterEngine 都有一定的預熱時間。這意味著啟動標準的 FlutterActivity 時,在 Flutter 體驗變得可見之前會有短暫的延遲。為了減少這種延遲,您可以在到達 FlutterActivity 之前預熱 FlutterEngine,然後使用預熱後的 FlutterEngine。
要預熱 FlutterEngine,請在應用中找一個合適的位置例項化 FlutterEngine。以下示例演示了在 Application 類中預熱 FlutterEngine:
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)
}
}
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 傳遞給任何應該使用該快取 FlutterEngine 的 FlutterActivity 或 FlutterFragment。接下來將討論如何將 FlutterActivity 與快取的 FlutterEngine 一起使用。
有了預熱後的快取 FlutterEngine,您現在需要指示 FlutterActivity 使用該快取引擎,而不是建立一個新的。為此,請使用 FlutterActivity 的 withCachedEngine() 構建器:
myButton.setOnClickListener {
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(this)
)
}
myButton.addOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(currentActivity)
);
}
});
使用 withCachedEngine() 工廠方法時,請傳遞與快取所需 FlutterEngine 時使用的相同的 ID。
現在,當您啟動 FlutterActivity 時,Flutter 內容顯示的延遲會顯著減少。
快取引擎的初始路由
#在配置帶有新 FlutterEngine 的 FlutterActivity 或 FlutterFragment 時,可以使用初始路由的概念。然而,當使用快取引擎時,FlutterActivity 和 FlutterFragment 不提供初始路由的概念。這是因為快取的引擎預期已經在執行 Dart 程式碼,這意味著現在配置初始路由為時已晚。
開發者如果希望其快取引擎以自定義初始路由啟動,可以在執行 Dart 入口點之前,配置其快取的 FlutterEngine 以使用自定義初始路由。以下示例展示瞭如何在快取引擎中使用初始路由:
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)
}
}
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() 初次執行後更改導航通道的初始路由屬性不會產生任何效果。如果開發者希望在不同的 Activity 和 Fragment 之間使用相同的 FlutterEngine,並在這些介面之間切換路由,則需要設定方法通道(MethodChannel),並顯式指示 Dart 程式碼更改 Navigator 路由。
新增半透明的 Flutter 螢幕
#
大多數全屏 Flutter 體驗都是不透明的。然而,一些應用希望部署看起來像模態框的 Flutter 螢幕,例如對話方塊或底部工作表(bottom sheet)。Flutter 開箱即支援半透明的 FlutterActivity。
要使您的 FlutterActivity 半透明,請對建立和啟動 FlutterActivity 的常規流程進行以下更改。
第 1 步:使用支援透明度的主題
#對於以半透明背景渲染的 Activity,Android 需要一個特殊的主題屬性。請建立或更新具有以下屬性的 Android 主題:
<style name="MyTheme" parent="@style/MyParentTheme">
<item name="android:windowIsTranslucent">true</item>
</style>
然後,將該半透明主題應用於您的 FlutterActivity。
<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:
// 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)
);
// 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。