在 Android 应用中添加 Flutter 页面
了解如何在你现有的 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(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() 可以用于配置一个 FlutterActivity,它会在内部创建一个属于自己的 FlutterEngine 实例,这会有一个明显的初始化时间。另外一种可选的做法是让
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 可以是你想要的任何名称。确保 FlutterActivity 或 FlutterFragment
在使用缓存的
FlutterEngine 时,传递了同样的 ID。基于缓存的 FlutterEngine 来使用 FlutterActivity 会在后续讨论到。
要使用预热且缓存的 FlutterEngine 时,让你的 FlutterActivity 从缓存中获取 FlutterEngine,而不是创建一个新的。可以使用 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 设置初始路由
#
在配置带有新 FlutterEngine 的 FlutterActivity 或 FlutterFragment 时,可以使用 initial route(初始路由)这一概念。
但是,在使用缓存 engine 时,FlutterActivity 和 FlutterFragment 不提供 initial route 这一概念。
这是因为缓存 engine 预期已经在运行 Dart 代码,这意味着配置 initial route 为时已晚。
希望缓存 engine 以自定义 initial route 开始的开发者,可以在执行 Dart entrypoint 之前,为缓存的 FlutterEngine 配置自定义 initial route。以下示例演示了如何在缓存 engine 中使用 initial route:
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);
}
}
通过设置 navigation channel 的 initial route,关联的 FlutterEngine 会在首次执行 runApp() Dart 函数时显示所需路由。
在首次执行 runApp() 之后更改 navigation channel 的 initial route 属性不会生效。如果开发者希望在不同的 Activity 和 Fragment 之间复用同一个 FlutterEngine,并在这些界面之间切换路由,则需要设置 method channel,并显式指示 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(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)
);
现在你的 FlutterAcivity 的背景已经是透明的了。
除非另有说明,本文档之所提及适用于 Flutter 3.44.0 版本。本页面最后更新时间:2026-05-05。查看文档源码 或者 为本页面内容提出建议。