Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit ea6fe7e

Browse files
committed
add the feature that can create a new engine with FlutterEngineGroup for FlutterActivity/FlutterFragment
1 parent a86ce6b commit ea6fe7e

17 files changed

+894
-6
lines changed

ci/licenses_golden/licenses_flutter

+1
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/Flutte
836836
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngineCache.java
837837
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java
838838
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroup.java
839+
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroupCache.java
839840
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
840841
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterOverlaySurface.java
841842
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java

shell/platform/android/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ android_java_sources = [
182182
"io/flutter/embedding/engine/FlutterEngineCache.java",
183183
"io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java",
184184
"io/flutter/embedding/engine/FlutterEngineGroup.java",
185+
"io/flutter/embedding/engine/FlutterEngineGroupCache.java",
185186
"io/flutter/embedding/engine/FlutterJNI.java",
186187
"io/flutter/embedding/engine/FlutterOverlaySurface.java",
187188
"io/flutter/embedding/engine/FlutterShellArgs.java",

shell/platform/android/io/flutter/embedding/android/FlutterActivity.java

+143-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_DART_ENTRYPOINT;
1010
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
1111
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_BACKGROUND_MODE;
12+
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID;
1213
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_ID;
14+
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DART_ENTRYPOINT;
1315
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DESTROY_ENGINE_WITH_ACTIVITY;
1416
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_ENABLE_STATE_RESTORATION;
1517
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_INITIAL_ROUTE;
@@ -269,7 +271,7 @@ public NewEngineIntentBuilder(@NonNull Class<? extends FlutterActivity> activity
269271
}
270272

271273
/**
272-
* The initial route that a Flutter app will render in this {@link FlutterFragment}, defaults to
274+
* The initial route that a Flutter app will render in this {@link FlutterActivity}, defaults to
273275
* "/".
274276
*
275277
* @param initialRoute The route.
@@ -421,6 +423,120 @@ public Intent build(@NonNull Context context) {
421423
}
422424
}
423425

426+
/**
427+
* Creates a {@link NewEngineInGroupIntentBuilder}, which can be used to configure an {@link
428+
* Intent} to launch a {@code FlutterActivity} that internally uses an existing {@link
429+
* io.flutter.embedding.engine.FlutterEngineGroup} that is cached in {@link
430+
* io.flutter.embedding.engine.FlutterEngineGroupCache}. and creates a new {@link
431+
* io.flutter.embedding.engine.FlutterEngine} by FlutterEngineGroup#createAndRunEngine
432+
*
433+
* @param engineGroupId A cached engine group ID.
434+
* @return The builder.
435+
*/
436+
public static NewEngineInGroupIntentBuilder withNewEngineInGroup(@NonNull String engineGroupId) {
437+
return new NewEngineInGroupIntentBuilder(FlutterActivity.class, engineGroupId);
438+
}
439+
440+
/**
441+
* Builder to create an {@code Intent} that launches a {@code FlutterActivity} with a new {@link
442+
* FlutterEngine} by FlutterEngineGroup#createAndRunEngine.
443+
*/
444+
public static class NewEngineInGroupIntentBuilder {
445+
private final Class<? extends FlutterActivity> activityClass;
446+
private final String cachedEngineGroupId;
447+
private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT;
448+
private String initialRoute = DEFAULT_INITIAL_ROUTE;
449+
private String backgroundMode = DEFAULT_BACKGROUND_MODE;
450+
451+
/**
452+
* Constructor that allows this {@code NewEngineInGroupIntentBuilder} to be used by subclasses
453+
* of {@code FlutterActivity}.
454+
*
455+
* <p>Subclasses of {@code FlutterActivity} should provide their own static version of {@link
456+
* #withNewEngineInGroup}, which returns an instance of {@code NewEngineInGroupIntentBuilder}
457+
* constructed with a {@code Class} reference to the {@code FlutterActivity} subclass, e.g.:
458+
*
459+
* <p>{@code return new NewEngineInGroupIntentBuilder(MyFlutterActivity.class,
460+
* cacheedEngineGroupId); }
461+
*
462+
* @param activityClass A subclass of {@code FlutterActivity}.
463+
* @param engineGroupId The engine group id.
464+
*/
465+
public NewEngineInGroupIntentBuilder(
466+
@NonNull Class<? extends FlutterActivity> activityClass, @NonNull String engineGroupId) {
467+
this.activityClass = activityClass;
468+
this.cachedEngineGroupId = engineGroupId;
469+
}
470+
471+
/**
472+
* The Dart entrypoint that will be executed as soon as the Dart snapshot is loaded, default to
473+
* "main".
474+
*
475+
* @param dartEntrypoint The dart entrypoint's name
476+
* @return The engine group intent builder
477+
*/
478+
@NonNull
479+
public NewEngineInGroupIntentBuilder dartEntrypoint(@NonNull String dartEntrypoint) {
480+
this.dartEntrypoint = dartEntrypoint;
481+
return this;
482+
}
483+
484+
/**
485+
* The initial route that a Flutter app will render in this {@link FlutterActivity}, defaults to
486+
* "/".
487+
*
488+
* @param initialRoute The route.
489+
* @return The engine group intent builder.
490+
*/
491+
@NonNull
492+
public NewEngineInGroupIntentBuilder initialRoute(@NonNull String initialRoute) {
493+
this.initialRoute = initialRoute;
494+
return this;
495+
}
496+
497+
/**
498+
* The mode of {@code FlutterActivity}'s background, either {@link BackgroundMode#opaque} or
499+
* {@link BackgroundMode#transparent}.
500+
*
501+
* <p>The default background mode is {@link BackgroundMode#opaque}.
502+
*
503+
* <p>Choosing a background mode of {@link BackgroundMode#transparent} will configure the inner
504+
* {@link FlutterView} of this {@code FlutterActivity} to be configured with a {@link
505+
* FlutterTextureView} to support transparency. This choice has a non-trivial performance
506+
* impact. A transparent background should only be used if it is necessary for the app design
507+
* being implemented.
508+
*
509+
* <p>A {@code FlutterActivity} that is configured with a background mode of {@link
510+
* BackgroundMode#transparent} must have a theme applied to it that includes the following
511+
* property: {@code <item name="android:windowIsTranslucent">true</item>}.
512+
*
513+
* @param backgroundMode The background mode.
514+
* @return The engine group intent builder.
515+
*/
516+
@NonNull
517+
public NewEngineInGroupIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode) {
518+
this.backgroundMode = backgroundMode.name();
519+
return this;
520+
}
521+
522+
/**
523+
* Creates and returns an {@link Intent} that will launch a {@code FlutterActivity} with the
524+
* desired configuration.
525+
*
526+
* @param context The context. e.g. An Activity.
527+
* @return The intent.
528+
*/
529+
@NonNull
530+
public Intent build(@NonNull Context context) {
531+
return new Intent(context, activityClass)
532+
.putExtra(EXTRA_DART_ENTRYPOINT, dartEntrypoint)
533+
.putExtra(EXTRA_INITIAL_ROUTE, initialRoute)
534+
.putExtra(EXTRA_CACHED_ENGINE_GROUP_ID, cachedEngineGroupId)
535+
.putExtra(EXTRA_BACKGROUND_MODE, backgroundMode)
536+
.putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY, true);
537+
}
538+
}
539+
424540
// Delegate that runs all lifecycle and OS hook logic that is common between
425541
// FlutterActivity and FlutterFragment. See the FlutterActivityAndFragmentDelegate
426542
// implementation for details about why it exists.
@@ -775,6 +891,17 @@ public String getCachedEngineId() {
775891
return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
776892
}
777893

894+
/**
895+
* Returns the ID of a statically cached {@link io.flutter.embedding.engine.FlutterEngineGroup} to
896+
* use within this {@code FlutterActivity}, or {@code null} if this {@code FlutterActivity} does
897+
* not want to use a cached {@link io.flutter.embedding.engine.FlutterEngineGroup}.
898+
*/
899+
@Override
900+
@Nullable
901+
public String getCachedEngineGroupId() {
902+
return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_GROUP_ID);
903+
}
904+
778905
/**
779906
* Returns false if the {@link io.flutter.embedding.engine.FlutterEngine} backing this {@code
780907
* FlutterActivity} should outlive this {@code FlutterActivity}, or true to be destroyed when the
@@ -801,14 +928,26 @@ public boolean shouldDestroyEngineWithHost() {
801928
/**
802929
* The Dart entrypoint that will be executed as soon as the Dart snapshot is loaded.
803930
*
804-
* <p>This preference can be controlled by setting a {@code <meta-data>} called {@link
805-
* FlutterActivityLaunchConfigs#DART_ENTRYPOINT_META_DATA_KEY} within the Android manifest
806-
* definition for this {@code FlutterActivity}.
931+
* <p>This preference can be controlled with 2 methods:
932+
*
933+
* <ol>
934+
* <li>Pass a boolean as {@link FlutterActivityLaunchConfigs#EXTRA_DART_ENTRYPOINT} with the
935+
* launching {@code Intent}, or
936+
* <li>Set a {@code <meta-data>} called {@link
937+
* FlutterActivityLaunchConfigs#DART_ENTRYPOINT_META_DATA_KEY} within the Android manifest
938+
* definition for this {@code FlutterActivity}
939+
* </ol>
940+
*
941+
* If both preferences are set, the {@code Intent} preference takes priority.
807942
*
808943
* <p>Subclasses may override this method to directly control the Dart entrypoint.
809944
*/
810945
@NonNull
811946
public String getDartEntrypointFunctionName() {
947+
if (getIntent().hasExtra(EXTRA_DART_ENTRYPOINT)) {
948+
return getIntent().getStringExtra(EXTRA_DART_ENTRYPOINT);
949+
}
950+
812951
try {
813952
Bundle metaData = getMetaData();
814953
String desiredDartEntrypoint =

shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java

+37
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import io.flutter.Log;
2626
import io.flutter.embedding.engine.FlutterEngine;
2727
import io.flutter.embedding.engine.FlutterEngineCache;
28+
import io.flutter.embedding.engine.FlutterEngineGroup;
29+
import io.flutter.embedding.engine.FlutterEngineGroupCache;
2830
import io.flutter.embedding.engine.FlutterShellArgs;
2931
import io.flutter.embedding.engine.dart.DartExecutor;
3032
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
@@ -214,6 +216,10 @@ void onAttach(@NonNull Context context) {
214216
* <p>Second, the {@code host} is given an opportunity to provide a {@link
215217
* io.flutter.embedding.engine.FlutterEngine} via {@link Host#provideFlutterEngine(Context)}.
216218
*
219+
* <p>Third, the {@code host} is given an FluttenEngineGroup Id, then used a cached {@link
220+
* io.flutter.embedding.engine.FlutterEngineGroup} to create a new {@link FlutterEngine} by {@link
221+
* FlutterEngineGroup#createAndRunEngine}
222+
*
217223
* <p>If the {@code host} does not provide a {@link io.flutter.embedding.engine.FlutterEngine},
218224
* then a new {@link FlutterEngine} is instantiated.
219225
*/
@@ -242,6 +248,34 @@ void onAttach(@NonNull Context context) {
242248
return;
243249
}
244250

251+
// Third, check if the host wants to use a cached FlutterEngineGroup
252+
// and create new FlutterEngine by FlutterEngineGroup#createAndRunEngine
253+
String cachedEngineGroupId = host.getCachedEngineGroupId();
254+
if (cachedEngineGroupId != null) {
255+
FlutterEngineGroup flutterEngineGroup =
256+
FlutterEngineGroupCache.getInstance().get(cachedEngineGroupId);
257+
if (flutterEngineGroup == null) {
258+
throw new IllegalStateException(
259+
"The requested cached FlutterEngineGroup did not exist in the FlutterEngineGroupCache: '"
260+
+ cachedEngineGroupId
261+
+ "'");
262+
}
263+
264+
String appBundlePathOverride = host.getAppBundlePath();
265+
if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) {
266+
appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
267+
}
268+
269+
DartExecutor.DartEntrypoint dartEntrypoint =
270+
new DartExecutor.DartEntrypoint(
271+
appBundlePathOverride, host.getDartEntrypointFunctionName());
272+
flutterEngine =
273+
flutterEngineGroup.createAndRunEngine(
274+
host.getContext(), dartEntrypoint, host.getInitialRoute());
275+
isFlutterEngineFromHost = false;
276+
return;
277+
}
278+
245279
// Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our
246280
// FlutterView.
247281
Log.v(
@@ -880,6 +914,9 @@ private void ensureAlive() {
880914
@Nullable
881915
String getCachedEngineId();
882916

917+
@Nullable
918+
String getCachedEngineGroupId();
919+
883920
/**
884921
* Returns true if the {@link io.flutter.embedding.engine.FlutterEngine} used in this delegate
885922
* should be destroyed when the host/delegate are destroyed.

shell/platform/android/io/flutter/embedding/android/FlutterActivityLaunchConfigs.java

+2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ public class FlutterActivityLaunchConfigs {
1919
/* package */ static final String HANDLE_DEEPLINKING_META_DATA_KEY =
2020
"flutter_deeplinking_enabled";
2121
// Intent extra arguments.
22+
/* package */ static final String EXTRA_DART_ENTRYPOINT = "dart_entrypoint";
2223
/* package */ static final String EXTRA_INITIAL_ROUTE = "route";
2324
/* package */ static final String EXTRA_BACKGROUND_MODE = "background_mode";
2425
/* package */ static final String EXTRA_CACHED_ENGINE_ID = "cached_engine_id";
26+
/* package */ static final String EXTRA_CACHED_ENGINE_GROUP_ID = "cached_engine_group_id";
2527
/* package */ static final String EXTRA_DESTROY_ENGINE_WITH_ACTIVITY =
2628
"destroy_engine_with_activity";
2729
/* package */ static final String EXTRA_ENABLE_STATE_RESTORATION = "enable_state_restoration";

0 commit comments

Comments
 (0)