-
Notifications
You must be signed in to change notification settings - Fork 6k
[WIP]add the feature that can create a new engine with FlutterEngineGroup … #29293
Changes from all commits
ea6fe7e
eb2d4d8
b61668d
c067104
af1418f
87dcfce
eab1e7c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,9 @@ | |
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_DART_ENTRYPOINT; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_BACKGROUND_MODE; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_ID; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DART_ENTRYPOINT; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DESTROY_ENGINE_WITH_ACTIVITY; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_ENABLE_STATE_RESTORATION; | ||
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_INITIAL_ROUTE; | ||
|
@@ -269,7 +271,7 @@ public NewEngineIntentBuilder(@NonNull Class<? extends FlutterActivity> activity | |
} | ||
|
||
/** | ||
* The initial route that a Flutter app will render in this {@link FlutterFragment}, defaults to | ||
* The initial route that a Flutter app will render in this {@link FlutterActivity}, defaults to | ||
* "/". | ||
* | ||
* @param initialRoute The route. | ||
|
@@ -421,6 +423,151 @@ public Intent build(@NonNull Context context) { | |
} | ||
} | ||
|
||
/** | ||
* Creates a {@link NewEngineInGroupIntentBuilder}, which can be used to configure an {@link | ||
* Intent} to launch a {@code FlutterActivity} by internally creating a FlutterEngine from an | ||
* existing {@link io.flutter.embedding.engine.FlutterEngineGroup} cached in a specified {@link | ||
* io.flutter.embedding.engine.FlutterEngineGroupCache}, and creates a new {@link | ||
* io.flutter.embedding.engine.FlutterEngine} by FlutterEngineGroup#createAndRunEngine | ||
* | ||
* <pre>{@code | ||
* // Create a FlutterEngineGroup, usually we could create it in onCreate method of Application. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a FlutterEngineGroup, such as in the onCreate method of the Application |
||
* FlutterEngineGroup engineGroup = new FlutterEngineGroup(this); | ||
* FlutterEngineGroupCache.getInstance().put("my_cached_engine_group_id", engineGroup); | ||
* | ||
* // use the intent that build by withNewEngineInGroup to start FlutterActivity | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Start a FlutterActivity with the FlutterEngineGroup by creating an intent with withNewEngineInGroup |
||
* Intent intent = FlutterActivity.withNewEngineInGroup("my_cached_engine_group_id") | ||
* .dartEntrypoint("custom_entrypoint") | ||
* .initialRoute("/custom/route") | ||
* .backgroundMode(BackgroundMode.transparent) | ||
* .build(context); | ||
* startActivity(intent); | ||
* }</pre> | ||
* | ||
* @param engineGroupId A cached engine group ID. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we add a code snippet that demonstrates a correct use of this method? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
* @return The builder. | ||
*/ | ||
public static NewEngineInGroupIntentBuilder withNewEngineInGroup(@NonNull String engineGroupId) { | ||
return new NewEngineInGroupIntentBuilder(FlutterActivity.class, engineGroupId); | ||
} | ||
|
||
/** | ||
* Builder to create an {@code Intent} that launches a {@code FlutterActivity} with a new {@link | ||
* FlutterEngine} by FlutterEngineGroup#createAndRunEngine. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. with a new {@link FlutterEngine} created by FlutterEngineGroup#createAndRunEngine. |
||
*/ | ||
public static class NewEngineInGroupIntentBuilder { | ||
private final Class<? extends FlutterActivity> activityClass; | ||
private final String cachedEngineGroupId; | ||
private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT; | ||
private String initialRoute = DEFAULT_INITIAL_ROUTE; | ||
private String backgroundMode = DEFAULT_BACKGROUND_MODE; | ||
|
||
/** | ||
* Constructor that allows this {@code NewEngineInGroupIntentBuilder} to be used by subclasses | ||
* of {@code FlutterActivity}. | ||
* | ||
* <p>Subclasses of {@code FlutterActivity} should provide their own static version of {@link | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment: an example would be helpful There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
* #withNewEngineInGroup}, which returns an instance of {@code NewEngineInGroupIntentBuilder} | ||
* constructed with a {@code Class} reference to the {@code FlutterActivity} subclass, e.g.: | ||
* | ||
* <p>{@code return new NewEngineInGroupIntentBuilder(MyFlutterActivity.class, | ||
* cacheedEngineGroupId); } | ||
* | ||
* <pre>{@code | ||
* // Create a FlutterEngineGroup, usually we could create it in onCreate method of Application. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a FlutterEngineGroup, such as in the onCreate method of the Application |
||
* FlutterEngineGroup engineGroup = new FlutterEngineGroup(this); | ||
* FlutterEngineGroupCache.getInstance().put("my_cached_engine_group_id", engineGroup); | ||
* | ||
* // create NewEngineInGroupIntentBuilder, and start my custom FlutterActivity with the intent | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a NewEngineInGroupIntentBuilder that would build an intent to start my custom FlutterActivity subclass. |
||
* // that build by NewEngineInGroupIntentBuilder. | ||
* FlutterActivity.NewEngineInGroupIntentBuilder intentBuilder = | ||
* new FlutterActivity.NewEngineInGroupIntentBuilder( | ||
* MyFlutterActivity.class, | ||
* app.engineGroupId); | ||
* intentBuilder.dartEntrypoint("main") | ||
* .initialRoute("/custom/route") | ||
* .backgroundMode(BackgroundMode.transparent); | ||
* startActivity(intentBuilder.build(context)); | ||
* }</pre> | ||
* | ||
* @param activityClass A subclass of {@code FlutterActivity}. | ||
* @param engineGroupId The engine group id. | ||
*/ | ||
public NewEngineInGroupIntentBuilder( | ||
@NonNull Class<? extends FlutterActivity> activityClass, @NonNull String engineGroupId) { | ||
this.activityClass = activityClass; | ||
this.cachedEngineGroupId = engineGroupId; | ||
} | ||
|
||
/** | ||
* The Dart entrypoint that will be executed in the newly created FlutterEngine as soon as the | ||
* Dart snapshot is loaded. Default to "main". | ||
* | ||
* @param dartEntrypoint The dart entrypoint's name | ||
* @return The engine group intent builder | ||
*/ | ||
@NonNull | ||
public NewEngineInGroupIntentBuilder dartEntrypoint(@NonNull String dartEntrypoint) { | ||
this.dartEntrypoint = dartEntrypoint; | ||
return this; | ||
} | ||
|
||
/** | ||
* The initial route that a Flutter app will render in this {@link FlutterActivity}, defaults to | ||
* "/". | ||
* | ||
* @param initialRoute The route. | ||
* @return The engine group intent builder. | ||
*/ | ||
@NonNull | ||
public NewEngineInGroupIntentBuilder initialRoute(@NonNull String initialRoute) { | ||
this.initialRoute = initialRoute; | ||
return this; | ||
} | ||
|
||
/** | ||
* The mode of {@code FlutterActivity}'s background, either {@link BackgroundMode#opaque} or | ||
* {@link BackgroundMode#transparent}. | ||
* | ||
* <p>The default background mode is {@link BackgroundMode#opaque}. | ||
* | ||
* <p>Choosing a background mode of {@link BackgroundMode#transparent} will configure the inner | ||
* {@link FlutterView} of this {@code FlutterActivity} to be configured with a {@link | ||
* FlutterTextureView} to support transparency. This choice has a non-trivial performance | ||
* impact. A transparent background should only be used if it is necessary for the app design | ||
* being implemented. | ||
* | ||
* <p>A {@code FlutterActivity} that is configured with a background mode of {@link | ||
* BackgroundMode#transparent} must have a theme applied to it that includes the following | ||
* property: {@code <item name="android:windowIsTranslucent">true</item>}. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in app/src/main/res/values/styles.xml right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, in app/src/main/res/values/styles.xml, we can define custom theme for activity, and set the background of activity. |
||
* | ||
* @param backgroundMode The background mode. | ||
* @return The engine group intent builder. | ||
*/ | ||
@NonNull | ||
public NewEngineInGroupIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rather than copying all this stuff again, can't we have them both be in the same builder class? Just have 2 constructors. One with an engine id and one with a engine group id. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes , we can have them both be in the same builder class. But this break Single Responsibility Principle. |
||
this.backgroundMode = backgroundMode.name(); | ||
return this; | ||
} | ||
|
||
/** | ||
* Creates and returns an {@link Intent} that will launch a {@code FlutterActivity} with the | ||
* desired configuration. | ||
* | ||
* @param context The context. e.g. An Activity. | ||
* @return The intent. | ||
*/ | ||
@NonNull | ||
public Intent build(@NonNull Context context) { | ||
return new Intent(context, activityClass) | ||
.putExtra(EXTRA_DART_ENTRYPOINT, dartEntrypoint) | ||
.putExtra(EXTRA_INITIAL_ROUTE, initialRoute) | ||
.putExtra(EXTRA_CACHED_ENGINE_GROUP_ID, cachedEngineGroupId) | ||
.putExtra(EXTRA_BACKGROUND_MODE, backgroundMode) | ||
.putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY, true); | ||
} | ||
} | ||
|
||
// Delegate that runs all lifecycle and OS hook logic that is common between | ||
// FlutterActivity and FlutterFragment. See the FlutterActivityAndFragmentDelegate | ||
// implementation for details about why it exists. | ||
|
@@ -775,6 +922,17 @@ public String getCachedEngineId() { | |
return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID); | ||
} | ||
|
||
/** | ||
* Returns the ID of a statically cached {@link io.flutter.embedding.engine.FlutterEngineGroup} to | ||
* use within this {@code FlutterActivity}, or {@code null} if this {@code FlutterActivity} does | ||
* not want to use a cached {@link io.flutter.embedding.engine.FlutterEngineGroup}. | ||
*/ | ||
@Override | ||
@Nullable | ||
public String getCachedEngineGroupId() { | ||
return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_GROUP_ID); | ||
} | ||
|
||
/** | ||
* Returns false if the {@link io.flutter.embedding.engine.FlutterEngine} backing this {@code | ||
* FlutterActivity} should outlive this {@code FlutterActivity}, or true to be destroyed when the | ||
|
@@ -801,14 +959,26 @@ public boolean shouldDestroyEngineWithHost() { | |
/** | ||
* The Dart entrypoint that will be executed as soon as the Dart snapshot is loaded. | ||
* | ||
* <p>This preference can be controlled by setting a {@code <meta-data>} called {@link | ||
* FlutterActivityLaunchConfigs#DART_ENTRYPOINT_META_DATA_KEY} within the Android manifest | ||
* definition for this {@code FlutterActivity}. | ||
* <p>This preference can be controlled with 2 methods: | ||
* | ||
* <ol> | ||
* <li>Pass a boolean as {@link FlutterActivityLaunchConfigs#EXTRA_DART_ENTRYPOINT} with the | ||
* launching {@code Intent}, or | ||
* <li>Set a {@code <meta-data>} called {@link | ||
* FlutterActivityLaunchConfigs#DART_ENTRYPOINT_META_DATA_KEY} within the Android manifest | ||
* definition for this {@code FlutterActivity} | ||
* </ol> | ||
* | ||
* If both preferences are set, the {@code Intent} preference takes priority. | ||
* | ||
* <p>Subclasses may override this method to directly control the Dart entrypoint. | ||
*/ | ||
@NonNull | ||
public String getDartEntrypointFunctionName() { | ||
if (getIntent().hasExtra(EXTRA_DART_ENTRYPOINT)) { | ||
return getIntent().getStringExtra(EXTRA_DART_ENTRYPOINT); | ||
} | ||
|
||
try { | ||
Bundle metaData = getMetaData(); | ||
String desiredDartEntrypoint = | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -24,6 +24,8 @@ | |||||||||||
import io.flutter.Log; | ||||||||||||
import io.flutter.embedding.engine.FlutterEngine; | ||||||||||||
import io.flutter.embedding.engine.FlutterEngineCache; | ||||||||||||
import io.flutter.embedding.engine.FlutterEngineGroup; | ||||||||||||
import io.flutter.embedding.engine.FlutterEngineGroupCache; | ||||||||||||
import io.flutter.embedding.engine.FlutterShellArgs; | ||||||||||||
import io.flutter.embedding.engine.dart.DartExecutor; | ||||||||||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener; | ||||||||||||
|
@@ -213,6 +215,10 @@ void onAttach(@NonNull Context context) { | |||||||||||
* <p>Second, the {@code host} is given an opportunity to provide a {@link | ||||||||||||
* io.flutter.embedding.engine.FlutterEngine} via {@link Host#provideFlutterEngine(Context)}. | ||||||||||||
* | ||||||||||||
* <p>Third, the {@code host} is given an FluttenEngineGroup Id, then used a cached {@link | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this statement doesn't match the code below? The host is asked whether it would like to provide a cached FlutterEngineGroup id rather than being given one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, you are right. I will update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
* io.flutter.embedding.engine.FlutterEngineGroup} to create a new {@link FlutterEngine} by {@link | ||||||||||||
* FlutterEngineGroup#createAndRunEngine} | ||||||||||||
* | ||||||||||||
* <p>If the {@code host} does not provide a {@link io.flutter.embedding.engine.FlutterEngine}, | ||||||||||||
* then a new {@link FlutterEngine} is instantiated. | ||||||||||||
*/ | ||||||||||||
|
@@ -241,6 +247,34 @@ void onAttach(@NonNull Context context) { | |||||||||||
return; | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Third, check if the host wants to use a cached FlutterEngineGroup | ||||||||||||
// and create new FlutterEngine by FlutterEngineGroup#createAndRunEngine | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
String cachedEngineGroupId = host.getCachedEngineGroupId(); | ||||||||||||
if (cachedEngineGroupId != null) { | ||||||||||||
FlutterEngineGroup flutterEngineGroup = | ||||||||||||
FlutterEngineGroupCache.getInstance().get(cachedEngineGroupId); | ||||||||||||
if (flutterEngineGroup == null) { | ||||||||||||
throw new IllegalStateException( | ||||||||||||
"The requested cached FlutterEngineGroup did not exist in the FlutterEngineGroupCache: '" | ||||||||||||
+ cachedEngineGroupId | ||||||||||||
+ "'"); | ||||||||||||
} | ||||||||||||
|
||||||||||||
String appBundlePathOverride = host.getAppBundlePath(); | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this block seems unrelated to the proposed change and is a scope creep right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because the Constructor of DartEntrypoint need 2 params. One is AppBundlePath, this block provide it from Host or FlutterLoader |
||||||||||||
if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) { | ||||||||||||
appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath(); | ||||||||||||
} | ||||||||||||
|
||||||||||||
DartExecutor.DartEntrypoint dartEntrypoint = | ||||||||||||
new DartExecutor.DartEntrypoint( | ||||||||||||
appBundlePathOverride, host.getDartEntrypointFunctionName()); | ||||||||||||
flutterEngine = | ||||||||||||
flutterEngineGroup.createAndRunEngine( | ||||||||||||
host.getContext(), dartEntrypoint, host.getInitialRoute()); | ||||||||||||
isFlutterEngineFromHost = false; | ||||||||||||
return; | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our | ||||||||||||
// FlutterView. | ||||||||||||
Log.v( | ||||||||||||
|
@@ -876,6 +910,9 @@ private void ensureAlive() { | |||||||||||
@Nullable | ||||||||||||
String getCachedEngineId(); | ||||||||||||
|
||||||||||||
@Nullable | ||||||||||||
String getCachedEngineGroupId(); | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* Returns true if the {@link io.flutter.embedding.engine.FlutterEngine} used in this delegate | ||||||||||||
* should be destroyed when the host/delegate are destroyed. | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can remove the last sentence