在 Android 應用中新增 Flutter 頁面
本指南講述瞭如何在一個現有的 Android 應用中新增單個 Flutter 頁面。新增到應用中的單個 Flutter 頁面可以是不透明的普通頁面,也可以是透明的頁面。這兩種頁面的使用都會在本指南中提到。
新增一個普通的 Flutter 頁面
步驟 1:在 AndroidManifest.xml 中新增 FlutterActivity
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.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity.createDefaultIntent(currentActivity)
);
}
});
myButton.setOnClickListener {
startActivity(
FlutterActivity.createDefaultIntent(this)
)
}
上述的例子假定了你的 Dart 程式碼入口是呼叫 main()
,並且你的 Flutter 初始路由是 ‘/’。
Dart 程式碼入口不能透過 Intent
改變,但是初始路由可以透過 Intent
來修改。下面的例子講解了如何開啟一個自訂 Flutter 初始路由的 FlutterActivity
。
myButton.addOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/my_route")
.build(currentActivity)
);
}
});
myButton.setOnClickListener {
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/my_route")
.build(this)
)
}
可以用你想要的初始路由替換掉 "/my_route"
。
工廠方法 withNewEngine()
可以用於配置一個 FlutterActivity
,它會在內部建立一個屬於自己的 FlutterEngine
例項,這會有一個明顯的初始化時間。另外一種可選的做法是讓
FlutterActivity
使用一個預熱且快取的 FlutterEngine
,這可以最小化 Flutter 初始化的時間。這種方式接下來會討論到。
步驟 3:(可選)使用快取的 FlutterEngine
每一個 FlutterActivity
預設會建立它自己的 FlutterEngine
。每一個 FlutterEngine
會有一個明顯的預熱時間。這意味著載入一個標準的 FlutterActivity
時,在你的 Flutter 互動頁面可見之前會有一個短暫的延遲。想要最小化這個延遲時間,你可以在抵達你的 FlutterActivity
之前,初始化一個 FlutterEngine
,然後使用這個已經預熱好的 FlutterEngine
。
要預熱一個 FlutterEngine
,可以在你的應用中找一個合理的地方例項化一個 FlutterEngine
。下面的這個例子是在 Application
類中預先初始化一個 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);
}
}
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)
}
}
傳給 FlutterEngineCache
的 ID 可以是你想要的任何名稱。確保 FlutterActivity
或 FlutterFragment
在使用快取的
FlutterEngine
時,傳遞了同樣的 ID。基於快取的 FlutterEngine
來使用 FlutterActivity
會在後續討論到。
要使用預熱且快取的 FlutterEngine
時,讓你的 FlutterActivity
從快取中獲取 FlutterEngine
,而不是建立一個新的。可以使用 FlutterActivity
的 withCachedEngine()
方法來實現:
myButton.addOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(currentActivity)
);
}
});
myButton.setOnClickListener {
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(this)
)
}
當使用 withCachedEngine()
方法時,傳遞你快取對應 FlutterEngine
時用的相同 ID。
現在,當你載入 FlutterActivity
時,在展示 Flutter 內容前的延遲會明顯降低。
為快取的 FlutterEngine 設定初始路由
當配置一個使用新 FlutterEngine
的 FlutterActivity
或者 FlutterFragment
時,會使用到初始路由的概念。但是,使用快取中的 Flutter 引擎時,
FlutterActivity
或者 FlutterFragment
則沒有涉及初始路由的概念。這是因為被快取的引擎理論上已經執行了 Dart 程式碼,在這時配置初始路由已經太遲了。
開發者如果想要讓快取中的引擎從自訂的初始路由開始執行,那麼可以執行 Dart 入口前,為快取的 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);
}
}
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)
}
}
透過設定導航通道中的初始路由,會讓關聯的 FlutterEngine
在 runApp()
方法首次執行後,展示已配置的路由頁面。
在 runApp()
的首次執行之後,修改導航通道中的初始路由屬性是不會生效的。想要在不同的 Activity
和 Fragment
之間使用同一個 FlutterEngine
,並且在其展示時切換不同的路由,開發者需要設定一個方法通道,來明確地通知他們的 Dart 程式碼切換 Navigator
路由。
新增一個透明主題的 FlutterActivity
大部分的全屏 Flutter 互動頁面是不透明的。但是,一些應用可能會發佈一個類似模態框的 Flutter 頁面,例如,一個對話方塊或者底部工作表。
Flutter 預設支援透明的 FlutterActivity
。
要將你的 FlutterActivity
設定為透明,在建立和載入 FlutterActivity
的常規步驟中做如下的變更。
步驟 1:使用透明的主題
Android 需要一個特殊的主題屬性來讓 Activity
以一個透明的背景渲染。使用如下屬性來建立或者修改一個 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(context)
);
// Using a cached FlutterEngine.
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
.build(context)
);
// 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)
);
現在你的 FlutterAcivity
的背景已經是透明的了。