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

Commit 7be0c36

Browse files
Make FlutterEngineGroup support initialRoute (#28884)
1 parent edf8fc8 commit 7be0c36

23 files changed

+204
-37
lines changed

shell/common/engine.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ std::unique_ptr<Engine> Engine::Spawn(
112112
Delegate& delegate,
113113
const PointerDataDispatcherMaker& dispatcher_maker,
114114
Settings settings,
115-
std::unique_ptr<Animator> animator) const {
115+
std::unique_ptr<Animator> animator,
116+
const std::string& initial_route) const {
116117
auto result = std::make_unique<Engine>(
117118
/*delegate=*/delegate,
118119
/*dispatcher_maker=*/dispatcher_maker,
@@ -133,6 +134,7 @@ std::unique_ptr<Engine> Engine::Spawn(
133134
settings_.isolate_shutdown_callback, // isolate shutdown callback
134135
settings_.persistent_isolate_data // persistent isolate data
135136
);
137+
result->initial_route_ = initial_route;
136138
return result;
137139
}
138140

shell/common/engine.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
375375
Delegate& delegate,
376376
const PointerDataDispatcherMaker& dispatcher_maker,
377377
Settings settings,
378-
std::unique_ptr<Animator> animator) const;
378+
std::unique_ptr<Animator> animator,
379+
const std::string& initial_route) const;
379380

380381
//----------------------------------------------------------------------------
381382
/// @brief Destroys the engine engine. Called by the shell on the UI task

shell/common/engine_unittests.cc

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,39 @@ TEST_F(EngineTest, SpawnSharesFontLibrary) {
268268
/*font_collection=*/std::make_shared<FontCollection>(),
269269
/*runtime_controller=*/std::move(mock_runtime_controller));
270270

271-
auto spawn =
272-
engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr);
271+
auto spawn = engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr,
272+
std::string());
273273
EXPECT_TRUE(spawn != nullptr);
274274
EXPECT_EQ(&engine->GetFontCollection(), &spawn->GetFontCollection());
275275
});
276276
}
277277

278+
TEST_F(EngineTest, SpawnWithCustomInitialRoute) {
279+
PostUITaskSync([this] {
280+
MockRuntimeDelegate client;
281+
auto mock_runtime_controller =
282+
std::make_unique<MockRuntimeController>(client, task_runners_);
283+
auto vm_ref = DartVMRef::Create(settings_);
284+
EXPECT_CALL(*mock_runtime_controller, GetDartVM())
285+
.WillRepeatedly(::testing::Return(vm_ref.get()));
286+
auto engine = std::make_unique<Engine>(
287+
/*delegate=*/delegate_,
288+
/*dispatcher_maker=*/dispatcher_maker_,
289+
/*image_decoder_task_runner=*/image_decoder_task_runner_,
290+
/*task_runners=*/task_runners_,
291+
/*settings=*/settings_,
292+
/*animator=*/std::move(animator_),
293+
/*io_manager=*/io_manager_,
294+
/*font_collection=*/std::make_shared<FontCollection>(),
295+
/*runtime_controller=*/std::move(mock_runtime_controller));
296+
297+
auto spawn =
298+
engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr, "/foo");
299+
EXPECT_TRUE(spawn != nullptr);
300+
ASSERT_EQ("/foo", spawn->InitialRoute());
301+
});
302+
}
303+
278304
TEST_F(EngineTest, PassesLoadDartDeferredLibraryErrorToRuntime) {
279305
PostUITaskSync([this] {
280306
intptr_t error_id = 123;

shell/common/shell.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ Shell::~Shell() {
480480

481481
std::unique_ptr<Shell> Shell::Spawn(
482482
RunConfiguration run_configuration,
483+
const std::string& initial_route,
483484
const CreateCallback<PlatformView>& on_create_platform_view,
484485
const CreateCallback<Rasterizer>& on_create_rasterizer) const {
485486
FML_DCHECK(task_runners_.IsValid());
@@ -488,7 +489,7 @@ std::unique_ptr<Shell> Shell::Spawn(
488489
PlatformData{}, task_runners_, rasterizer_->GetRasterThreadMerger(),
489490
GetSettings(), vm_, vm_->GetVMData()->GetIsolateSnapshot(),
490491
on_create_platform_view, on_create_rasterizer,
491-
[engine = this->engine_.get()](
492+
[engine = this->engine_.get(), initial_route](
492493
Engine::Delegate& delegate,
493494
const PointerDataDispatcherMaker& dispatcher_maker, DartVM& vm,
494495
fml::RefPtr<const DartSnapshot> isolate_snapshot,
@@ -501,7 +502,8 @@ std::unique_ptr<Shell> Shell::Spawn(
501502
return engine->Spawn(/*delegate=*/delegate,
502503
/*dispatcher_maker=*/dispatcher_maker,
503504
/*settings=*/settings,
504-
/*animator=*/std::move(animator));
505+
/*animator=*/std::move(animator),
506+
/*initial_route=*/initial_route);
505507
},
506508
is_gpu_disabled));
507509
return result;

shell/common/shell.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class Shell final : public PlatformView::Delegate,
194194
/// @see http://flutter.dev/go/multiple-engines
195195
std::unique_ptr<Shell> Spawn(
196196
RunConfiguration run_configuration,
197+
const std::string& initial_route,
197198
const CreateCallback<PlatformView>& on_create_platform_view,
198199
const CreateCallback<Rasterizer>& on_create_rasterizer) const;
199200

shell/common/shell_unittests.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,8 @@ TEST_F(ShellTest, Spawn) {
26952695
ASSERT_TRUE(second_configuration.IsValid());
26962696
second_configuration.SetEntrypoint("testCanLaunchSecondaryIsolate");
26972697

2698+
const std::string initial_route("/foo");
2699+
26982700
fml::AutoResetWaitableEvent main_latch;
26992701
std::string last_entry_point;
27002702
// Fulfill native function for the first Shell's entrypoint.
@@ -2719,10 +2721,11 @@ TEST_F(ShellTest, Spawn) {
27192721

27202722
PostSync(
27212723
shell->GetTaskRunners().GetPlatformTaskRunner(),
2722-
[this, &spawner = shell, &second_configuration, &second_latch]() {
2724+
[this, &spawner = shell, &second_configuration, &second_latch,
2725+
initial_route]() {
27232726
MockPlatformViewDelegate platform_view_delegate;
27242727
auto spawn = spawner->Spawn(
2725-
std::move(second_configuration),
2728+
std::move(second_configuration), initial_route,
27262729
[&platform_view_delegate](Shell& shell) {
27272730
auto result = std::make_unique<MockPlatformView>(
27282731
platform_view_delegate, shell.GetTaskRunners());
@@ -2736,10 +2739,11 @@ TEST_F(ShellTest, Spawn) {
27362739
ASSERT_TRUE(ValidateShell(spawn.get()));
27372740

27382741
PostSync(spawner->GetTaskRunners().GetUITaskRunner(),
2739-
[&spawn, &spawner] {
2742+
[&spawn, &spawner, initial_route] {
27402743
// Check second shell ran the second entrypoint.
27412744
ASSERT_EQ("testCanLaunchSecondaryIsolate",
27422745
spawn->GetEngine()->GetLastEntrypoint());
2746+
ASSERT_EQ(initial_route, spawn->GetEngine()->InitialRoute());
27432747

27442748
// TODO(74520): Remove conditional once isolate groups are
27452749
// supported by JIT.

shell/platform/android/android_shell_holder.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ const flutter::Settings& AndroidShellHolder::GetSettings() const {
174174
std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
175175
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
176176
const std::string& entrypoint,
177-
const std::string& libraryUrl) const {
177+
const std::string& libraryUrl,
178+
const std::string& initial_route) const {
178179
FML_DCHECK(shell_ && shell_->IsSetup())
179180
<< "A new Shell can only be spawned "
180181
"if the current Shell is properly constructed";
@@ -226,8 +227,9 @@ std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
226227
return nullptr;
227228
}
228229

229-
std::unique_ptr<flutter::Shell> shell = shell_->Spawn(
230-
std::move(config.value()), on_create_platform_view, on_create_rasterizer);
230+
std::unique_ptr<flutter::Shell> shell =
231+
shell_->Spawn(std::move(config.value()), initial_route,
232+
on_create_platform_view, on_create_rasterizer);
231233

232234
return std::unique_ptr<AndroidShellHolder>(
233235
new AndroidShellHolder(GetSettings(), jni_facade, thread_host_,

shell/platform/android/android_shell_holder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ class AndroidShellHolder {
7878
std::unique_ptr<AndroidShellHolder> Spawn(
7979
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
8080
const std::string& entrypoint,
81-
const std::string& libraryUrl) const;
81+
const std::string& libraryUrl,
82+
const std::string& initial_route) const;
8283

8384
void Launch(std::shared_ptr<AssetManager> asset_manager,
8485
const std::string& entrypoint,

shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,15 +384,19 @@ private boolean isAttachedToJni() {
384384
*/
385385
@NonNull
386386
/*package*/ FlutterEngine spawn(
387-
@NonNull Context context, @NonNull DartEntrypoint dartEntrypoint) {
387+
@NonNull Context context,
388+
@NonNull DartEntrypoint dartEntrypoint,
389+
@Nullable String initialRoute) {
388390
if (!isAttachedToJni()) {
389391
throw new IllegalStateException(
390392
"Spawn can only be called on a fully constructed FlutterEngine");
391393
}
392394

393395
FlutterJNI newFlutterJNI =
394396
flutterJNI.spawn(
395-
dartEntrypoint.dartEntrypointFunctionName, dartEntrypoint.dartEntrypointLibrary);
397+
dartEntrypoint.dartEntrypointFunctionName,
398+
dartEntrypoint.dartEntrypointLibrary,
399+
initialRoute);
396400
return new FlutterEngine(
397401
context, // Context.
398402
null, // FlutterLoader. A null value passed here causes the constructor to get it from the

shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroup.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,27 @@ public FlutterEngine createAndRunDefaultEngine(@NonNull Context context) {
9696
*/
9797
public FlutterEngine createAndRunEngine(
9898
@NonNull Context context, @Nullable DartEntrypoint dartEntrypoint) {
99+
return createAndRunEngine(context, dartEntrypoint, null);
100+
}
101+
102+
/**
103+
* Creates a {@link io.flutter.embedding.engine.FlutterEngine} in this group and run its {@link
104+
* io.flutter.embedding.engine.dart.DartExecutor} with the specified {@link DartEntrypoint} and
105+
* the specified {@code initialRoute}.
106+
*
107+
* <p>If no prior {@link io.flutter.embedding.engine.FlutterEngine} were created in this group,
108+
* the initialization cost will be slightly higher than subsequent engines. The very first {@link
109+
* io.flutter.embedding.engine.FlutterEngine} created per program, regardless of
110+
* FlutterEngineGroup, also incurs the Dart VM creation time.
111+
*
112+
* <p>Subsequent engine creations will share resources with existing engines. However, if all
113+
* existing engines were {@link io.flutter.embedding.engine.FlutterEngine#destroy()}ed, the next
114+
* engine created will recreate its dependencies.
115+
*/
116+
public FlutterEngine createAndRunEngine(
117+
@NonNull Context context,
118+
@Nullable DartEntrypoint dartEntrypoint,
119+
@Nullable String initialRoute) {
99120
FlutterEngine engine = null;
100121

101122
if (dartEntrypoint == null) {
@@ -104,9 +125,12 @@ public FlutterEngine createAndRunEngine(
104125

105126
if (activeEngines.size() == 0) {
106127
engine = createEngine(context);
128+
if (initialRoute != null) {
129+
engine.getNavigationChannel().setInitialRoute(initialRoute);
130+
}
107131
engine.getDartExecutor().executeDartEntrypoint(dartEntrypoint);
108132
} else {
109-
engine = activeEngines.get(0).spawn(context, dartEntrypoint);
133+
engine = activeEngines.get(0).spawn(context, dartEntrypoint, initialRoute);
110134
}
111135

112136
activeEngines.add(engine);

0 commit comments

Comments
 (0)