向 Android 应用中添加 Flutter 页面
This guide describes how to add a single Flutter screen to an existing Androidapp. A Flutter screen can be added as a normal, opaque screen, or as asee-through, translucent screen. Both options are described in this guide.
Add a normal Flutter screen
Step 1: Add FlutterActivity to AndroidManifest.xml
Flutter provides FlutterActivity
to display a Flutter experience within anAndroid app. Like any other Activity
, FlutterActivity
must beregistered in your AndroidManifest.xml
. Add the following XML to yourAndroidManifestxml
file under your application
tag:
<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"
/>
The reference to @style/LaunchTheme
can be replaced by any Android theme thatwant to apply to your FlutterActivity
. The choice of theme dictates thecolors applied to Android’s system chrome, like Android’s navigation bar, and tothe background color of the FlutterActivity
just before the Flutter UI renders itself for the first time.
Step 2: Launch FlutterActivity
With FlutterActivity
registered in your manifest file, add code to launchFlutterActivity
from whatever point in your app that you’d like. The followingexample shows FlutterActivity
being launched from an OnClickListener
.
ExistingActivity.java
- myButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(
- FlutterActivity.createDefaultIntent(currentActivity)
- );
- }
- });
ExistingActivity.kt
- myButton.setOnClickListener {
- startActivity(
- FlutterActivity.createDefaultIntent(this)
- )
- }
The previous example assumes that your Dart entrypoint is called main()
, and yourinitial Flutter route is ‘/’. The Dart entrypoint can’t be changed using Intent
,but the initial route can be changed using Intent
. The following exampledemonstrates how to launch a FlutterActivity
that initially renders a customroute in Flutter.
ExistingActivity.java
- myButton.addOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(
- FlutterActivity
- .withNewEngine()
- .initialRoute("/my_route")
- .build(currentActivity)
- );
- }
- });
ExistingActivity.kt
- myButton.setOnClickListener {
- startActivity(
- FlutterActivity
- .withNewEngine()
- .initialRoute("/my_route")
- .build(this)
- )
- }
Replace "/my_route"
with your desired initial route.
The use of the withNewEngine()
factory method configures a FlutterActivity
that internally create its own FlutterEngine
instance. This comes with a non-trivial initialization time. The alternative approach is to instructFlutterActivity
to use a pre-warmed, cached FlutterEngine
, which minimizesFlutter’s initialization time. That approach is discussed next.
Step 3: (Optional) Use a cached FlutterEngine
Every FlutterActivity
creates its own FlutterEngine
by default. EachFlutterEngine
has a non-trivial, warm-up time. This means that launching astandard FlutterActivity
comes with a brief delay before your Flutterexperience becomes visible. To minimize this delay, you can warm up aFlutterEngine
before arriving at your FlutterActivity
, and then you can useyour pre-warmed FlutterEngine
instead.
To pre-warm a FlutterEngine
, find a reasonable location in your app toinstantiate a FlutterEngine
. The following example arbitrarily pre-warms a FlutterEngine
in the Application
class:
MyApplication.java
- public class MyApplication extends Application {
- @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);
- }
- }
MyApplication.kt
- 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)
- }
- }
The ID passed to the FlutterEngineCache
can be whatever you want. Make surethat you pass the same ID to any FlutterActiity
or FlutterFragment
that should use the cached FlutterEngine
. Using FlutterActivity
with acached FlutterEngine
is discussed next.
备忘 To warm up a FlutterEngine
, you must execute a Dart entrypoint. Keep in mind that the moment executeDartEntrypoint()
is invoked, your Dart entrypoint method begins executing. If your Dart entrypoint invokes runApp()
to run a Flutter app, then your Flutter app behaves as if it were running in a window of zero size until this FlutterEngine
is attached to a FlutterActivity
, FlutterFragment
, or FlutterView
. Make sure that your app behaves appropriately between the time you warm it up and the time you display Flutter content.
With a pre-warmed, cached FlutterEngine
, you now need to instruct yourFlutterActivity
to use the cached FlutterEngine
instead of creating anew one. To accomplish this, use FlutterActivity
’s withCachedEngine()
builder:
ExistingActivity.java
- myButton.addOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(
- FlutterActivity
- .withCachedEngine("my_engine_id")
- .build(currentActivity)
- );
- }
- });
ExistingActivity.kt
- myButton.setOnClickListener {
- startActivity(
- FlutterActivity
- .withCachedEngine("my_engine_id")
- .build(this)
- )
- }
When using the withCachedEngine()
factory method, pass the same ID that youused when caching the desired FlutterEngine
.
Now, when you launch FlutterActivity
, there is significantly less delay inthe display of Flutter content.
备忘 When using a cached FlutterEngine
, that FlutterEngine
outlives any FlutterActivity
or FlutterFragment
that displays it. Keep in mind that Dart code begins executing as soon as you pre-warm the FlutterEngine
, and continues executing after the destruction of your FlutterActivity
/FlutterFragment
. To stop executing and clear resources, obtain your FlutterEngine
from the FlutterEngineCache
and destroy the FlutterEngine
with FlutterEngine.destroy()
.
备忘 Runtime performance isn’t the only reason that you might pre-warm and cache a FlutterEngine
. A pre-warmed FlutterEngine
executes Dart code independent from a FlutterActivity
, which allows such a FlutterEngine
to be used to execute arbitrary Dart code at any moment. Non-UI application logic can be executed in a FlutterEngine
, like networking and data caching, and in background behavior within a Service
or elsewhere. When using a FlutterEngine
to execute behavior in the background, be sure to adhere to all Android restrictions on background execution.
备忘 Flutter’s debug/release builds have drastically different performance characteristics. To evaluate the performance of Flutter, use a release build.
Add a translucent Flutter screen
Most full-screen Flutter experiences are opaque. However, some apps would like todeploy a Flutter screen that looks like a modal, for example, a dialog or bottom sheet. Flutter supports translucent FlutterActivity
s out of the box.
To make your FlutterActivity
translucent, make the following changes tothe regular process of creating and launching a FlutterActivity
.
Step 1: Use a theme with translucency
Android requires a special theme property for Activity
s that render with a translucent background. Create or update an Android theme with thefollowing property:
<style name="MyTheme" parent="@style/MyParentTheme">
<item name="android:windowIsTranslucent">true</item>
</style>
Then, apply the translucent theme to your 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"
/>
Your FlutterActivity
now supports translucency. Next, you need to launch yourFlutterActivity
with explicit transparency support.
Step 2: Start FlutterActivity with transparency
To launch your FlutterActivity
with a transparent background, pass theappropriate BackgroundMode
to the IntentBuilder
:
ExistingActivity.java
- // Using a new FlutterEngine.
- startActivity(
- FlutterActivity
- .withNewEngine()
- .backgroundMode(FlutterActivity.BackgroundMode.transparent)
- .build(context)
- );
- // Using a cached FlutterEngine.
- startActivity(
- FlutterActivity
- .withCachedEngine("my_engine_id")
- .backgroundMode(FlutterActivity.BackgroundMode.transparent)
- .build(context)
- );
ExistingActivity.kt
- // Using a new FlutterEngine.
- startActivity(
- FlutterActivity
- .withNewEngine()
- .backgroundMode(FlutterActivity.BackgroundMode.transparent)
- .build(this)
- );
- // Using a cached FlutterEngine.
- startActivity(
- FlutterActivity
- .withCachedEngine("my_engine_id")
- .backgroundMode(FlutterActivity.BackgroundMode.transparent)
- .build(this)
- );
You now have a FlutterActivity
with a transparent background.
备忘 Make sure that your Flutter content also includes a translucent background. If your Flutter UI paints a solid background color, then it still appears as though your FlutterActivity
has an opaque background.