向 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

Add Flutter Screen Header

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:

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

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

  1. myButton.setOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. startActivity(
  5. FlutterActivity.createDefaultIntent(currentActivity)
  6. );
  7. }
  8. });

ExistingActivity.kt

  1. myButton.setOnClickListener {
  2. startActivity(
  3. FlutterActivity.createDefaultIntent(this)
  4. )
  5. }

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

  1. myButton.addOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. startActivity(
  5. FlutterActivity
  6. .withNewEngine()
  7. .initialRoute("/my_route")
  8. .build(currentActivity)
  9. );
  10. }
  11. });

ExistingActivity.kt

  1. myButton.setOnClickListener {
  2. startActivity(
  3. FlutterActivity
  4. .withNewEngine()
  5. .initialRoute("/my_route")
  6. .build(this)
  7. )
  8. }

Replace "/my_route" with your desired initial route.

The use of the withNewEngine() factory method configures a FlutterActivitythat 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

  1. public class MyApplication extends Application {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. // Instantiate a FlutterEngine.
  6. flutterEngine = new FlutterEngine(this);
  7.  
  8. // Start executing Dart code to pre-warm the FlutterEngine.
  9. flutterEngine.getDartExecutor().executeDartEntrypoint(
  10. DartEntrypoint.createDefault()
  11. );
  12.  
  13. // Cache the FlutterEngine to be used by FlutterActivity.
  14. FlutterEngineCache
  15. .getInstance()
  16. .put("my_engine_id", flutterEngine);
  17. }
  18. }

MyApplication.kt

  1. class MyApplication : Application() {
  2. lateinit var flutterEngine : FlutterEngine
  3.  
  4. override fun onCreate() {
  5. super.onCreate()
  6.  
  7. // Instantiate a FlutterEngine.
  8. flutterEngine = FlutterEngine(this)
  9.  
  10. // Start executing Dart code to pre-warm the FlutterEngine.
  11. flutterEngine.dartExecutor.executeDartEntrypoint(
  12. DartExecutor.DartEntrypoint.createDefault()
  13. )
  14.  
  15. // Cache the FlutterEngine to be used by FlutterActivity.
  16. FlutterEngineCache
  17. .getInstance()
  18. .put("my_engine_id", flutterEngine)
  19. }
  20. }

The ID passed to the FlutterEngineCache can be whatever you want. Make surethat you pass the same ID to any FlutterActiity or FlutterFragmentthat 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

  1. myButton.addOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. startActivity(
  5. FlutterActivity
  6. .withCachedEngine("my_engine_id")
  7. .build(currentActivity)
  8. );
  9. }
  10. });

ExistingActivity.kt

  1. myButton.setOnClickListener {
  2. startActivity(
  3. FlutterActivity
  4. .withCachedEngine("my_engine_id")
  5. .build(this)
  6. )
  7. }

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

Add Flutter Screen With Translucency Header

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 FlutterActivitys 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 Activitys that render with a translucent background. Create or update an Android theme with thefollowing property:

  1. <style name="MyTheme" parent="@style/MyParentTheme">
  2. <item name="android:windowIsTranslucent">true</item>
  3. </style>

Then, apply the translucent theme to your FlutterActivity.

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

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

  1. // Using a new FlutterEngine.
  2. startActivity(
  3. FlutterActivity
  4. .withNewEngine()
  5. .backgroundMode(FlutterActivity.BackgroundMode.transparent)
  6. .build(context)
  7. );
  8.  
  9. // Using a cached FlutterEngine.
  10. startActivity(
  11. FlutterActivity
  12. .withCachedEngine("my_engine_id")
  13. .backgroundMode(FlutterActivity.BackgroundMode.transparent)
  14. .build(context)
  15. );

ExistingActivity.kt

  1. // Using a new FlutterEngine.
  2. startActivity(
  3. FlutterActivity
  4. .withNewEngine()
  5. .backgroundMode(FlutterActivity.BackgroundMode.transparent)
  6. .build(this)
  7. );
  8.  
  9. // Using a cached FlutterEngine.
  10. startActivity(
  11. FlutterActivity
  12. .withCachedEngine("my_engine_id")
  13. .backgroundMode(FlutterActivity.BackgroundMode.transparent)
  14. .build(this)
  15. );

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.