mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Make FlutterEngineGroup support initialRoute (flutter/engine#28884)
This commit is contained in:
parent
a3553b7f41
commit
3bd57ac05a
@ -112,7 +112,8 @@ std::unique_ptr<Engine> Engine::Spawn(
|
||||
Delegate& delegate,
|
||||
const PointerDataDispatcherMaker& dispatcher_maker,
|
||||
Settings settings,
|
||||
std::unique_ptr<Animator> animator) const {
|
||||
std::unique_ptr<Animator> animator,
|
||||
const std::string& initial_route) const {
|
||||
auto result = std::make_unique<Engine>(
|
||||
/*delegate=*/delegate,
|
||||
/*dispatcher_maker=*/dispatcher_maker,
|
||||
@ -133,6 +134,7 @@ std::unique_ptr<Engine> Engine::Spawn(
|
||||
settings_.isolate_shutdown_callback, // isolate shutdown callback
|
||||
settings_.persistent_isolate_data // persistent isolate data
|
||||
);
|
||||
result->initial_route_ = initial_route;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -375,7 +375,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
Delegate& delegate,
|
||||
const PointerDataDispatcherMaker& dispatcher_maker,
|
||||
Settings settings,
|
||||
std::unique_ptr<Animator> animator) const;
|
||||
std::unique_ptr<Animator> animator,
|
||||
const std::string& initial_route) const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Destroys the engine engine. Called by the shell on the UI task
|
||||
|
||||
@ -268,13 +268,39 @@ TEST_F(EngineTest, SpawnSharesFontLibrary) {
|
||||
/*font_collection=*/std::make_shared<FontCollection>(),
|
||||
/*runtime_controller=*/std::move(mock_runtime_controller));
|
||||
|
||||
auto spawn =
|
||||
engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr);
|
||||
auto spawn = engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr,
|
||||
std::string());
|
||||
EXPECT_TRUE(spawn != nullptr);
|
||||
EXPECT_EQ(&engine->GetFontCollection(), &spawn->GetFontCollection());
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(EngineTest, SpawnWithCustomInitialRoute) {
|
||||
PostUITaskSync([this] {
|
||||
MockRuntimeDelegate client;
|
||||
auto mock_runtime_controller =
|
||||
std::make_unique<MockRuntimeController>(client, task_runners_);
|
||||
auto vm_ref = DartVMRef::Create(settings_);
|
||||
EXPECT_CALL(*mock_runtime_controller, GetDartVM())
|
||||
.WillRepeatedly(::testing::Return(vm_ref.get()));
|
||||
auto engine = std::make_unique<Engine>(
|
||||
/*delegate=*/delegate_,
|
||||
/*dispatcher_maker=*/dispatcher_maker_,
|
||||
/*image_decoder_task_runner=*/image_decoder_task_runner_,
|
||||
/*task_runners=*/task_runners_,
|
||||
/*settings=*/settings_,
|
||||
/*animator=*/std::move(animator_),
|
||||
/*io_manager=*/io_manager_,
|
||||
/*font_collection=*/std::make_shared<FontCollection>(),
|
||||
/*runtime_controller=*/std::move(mock_runtime_controller));
|
||||
|
||||
auto spawn =
|
||||
engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr, "/foo");
|
||||
EXPECT_TRUE(spawn != nullptr);
|
||||
ASSERT_EQ("/foo", spawn->InitialRoute());
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(EngineTest, PassesLoadDartDeferredLibraryErrorToRuntime) {
|
||||
PostUITaskSync([this] {
|
||||
intptr_t error_id = 123;
|
||||
|
||||
@ -480,6 +480,7 @@ Shell::~Shell() {
|
||||
|
||||
std::unique_ptr<Shell> Shell::Spawn(
|
||||
RunConfiguration run_configuration,
|
||||
const std::string& initial_route,
|
||||
const CreateCallback<PlatformView>& on_create_platform_view,
|
||||
const CreateCallback<Rasterizer>& on_create_rasterizer) const {
|
||||
FML_DCHECK(task_runners_.IsValid());
|
||||
@ -488,7 +489,7 @@ std::unique_ptr<Shell> Shell::Spawn(
|
||||
PlatformData{}, task_runners_, rasterizer_->GetRasterThreadMerger(),
|
||||
GetSettings(), vm_, vm_->GetVMData()->GetIsolateSnapshot(),
|
||||
on_create_platform_view, on_create_rasterizer,
|
||||
[engine = this->engine_.get()](
|
||||
[engine = this->engine_.get(), initial_route](
|
||||
Engine::Delegate& delegate,
|
||||
const PointerDataDispatcherMaker& dispatcher_maker, DartVM& vm,
|
||||
fml::RefPtr<const DartSnapshot> isolate_snapshot,
|
||||
@ -501,7 +502,8 @@ std::unique_ptr<Shell> Shell::Spawn(
|
||||
return engine->Spawn(/*delegate=*/delegate,
|
||||
/*dispatcher_maker=*/dispatcher_maker,
|
||||
/*settings=*/settings,
|
||||
/*animator=*/std::move(animator));
|
||||
/*animator=*/std::move(animator),
|
||||
/*initial_route=*/initial_route);
|
||||
},
|
||||
is_gpu_disabled));
|
||||
return result;
|
||||
|
||||
@ -194,6 +194,7 @@ class Shell final : public PlatformView::Delegate,
|
||||
/// @see http://flutter.dev/go/multiple-engines
|
||||
std::unique_ptr<Shell> Spawn(
|
||||
RunConfiguration run_configuration,
|
||||
const std::string& initial_route,
|
||||
const CreateCallback<PlatformView>& on_create_platform_view,
|
||||
const CreateCallback<Rasterizer>& on_create_rasterizer) const;
|
||||
|
||||
|
||||
@ -2695,6 +2695,8 @@ TEST_F(ShellTest, Spawn) {
|
||||
ASSERT_TRUE(second_configuration.IsValid());
|
||||
second_configuration.SetEntrypoint("testCanLaunchSecondaryIsolate");
|
||||
|
||||
const std::string initial_route("/foo");
|
||||
|
||||
fml::AutoResetWaitableEvent main_latch;
|
||||
std::string last_entry_point;
|
||||
// Fulfill native function for the first Shell's entrypoint.
|
||||
@ -2719,10 +2721,11 @@ TEST_F(ShellTest, Spawn) {
|
||||
|
||||
PostSync(
|
||||
shell->GetTaskRunners().GetPlatformTaskRunner(),
|
||||
[this, &spawner = shell, &second_configuration, &second_latch]() {
|
||||
[this, &spawner = shell, &second_configuration, &second_latch,
|
||||
initial_route]() {
|
||||
MockPlatformViewDelegate platform_view_delegate;
|
||||
auto spawn = spawner->Spawn(
|
||||
std::move(second_configuration),
|
||||
std::move(second_configuration), initial_route,
|
||||
[&platform_view_delegate](Shell& shell) {
|
||||
auto result = std::make_unique<MockPlatformView>(
|
||||
platform_view_delegate, shell.GetTaskRunners());
|
||||
@ -2736,10 +2739,11 @@ TEST_F(ShellTest, Spawn) {
|
||||
ASSERT_TRUE(ValidateShell(spawn.get()));
|
||||
|
||||
PostSync(spawner->GetTaskRunners().GetUITaskRunner(),
|
||||
[&spawn, &spawner] {
|
||||
[&spawn, &spawner, initial_route] {
|
||||
// Check second shell ran the second entrypoint.
|
||||
ASSERT_EQ("testCanLaunchSecondaryIsolate",
|
||||
spawn->GetEngine()->GetLastEntrypoint());
|
||||
ASSERT_EQ(initial_route, spawn->GetEngine()->InitialRoute());
|
||||
|
||||
// TODO(74520): Remove conditional once isolate groups are
|
||||
// supported by JIT.
|
||||
|
||||
@ -174,7 +174,8 @@ const flutter::Settings& AndroidShellHolder::GetSettings() const {
|
||||
std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const std::string& entrypoint,
|
||||
const std::string& libraryUrl) const {
|
||||
const std::string& libraryUrl,
|
||||
const std::string& initial_route) const {
|
||||
FML_DCHECK(shell_ && shell_->IsSetup())
|
||||
<< "A new Shell can only be spawned "
|
||||
"if the current Shell is properly constructed";
|
||||
@ -226,8 +227,9 @@ std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<flutter::Shell> shell = shell_->Spawn(
|
||||
std::move(config.value()), on_create_platform_view, on_create_rasterizer);
|
||||
std::unique_ptr<flutter::Shell> shell =
|
||||
shell_->Spawn(std::move(config.value()), initial_route,
|
||||
on_create_platform_view, on_create_rasterizer);
|
||||
|
||||
return std::unique_ptr<AndroidShellHolder>(
|
||||
new AndroidShellHolder(GetSettings(), jni_facade, thread_host_,
|
||||
|
||||
@ -78,7 +78,8 @@ class AndroidShellHolder {
|
||||
std::unique_ptr<AndroidShellHolder> Spawn(
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const std::string& entrypoint,
|
||||
const std::string& libraryUrl) const;
|
||||
const std::string& libraryUrl,
|
||||
const std::string& initial_route) const;
|
||||
|
||||
void Launch(std::shared_ptr<AssetManager> asset_manager,
|
||||
const std::string& entrypoint,
|
||||
|
||||
@ -384,7 +384,9 @@ public class FlutterEngine {
|
||||
*/
|
||||
@NonNull
|
||||
/*package*/ FlutterEngine spawn(
|
||||
@NonNull Context context, @NonNull DartEntrypoint dartEntrypoint) {
|
||||
@NonNull Context context,
|
||||
@NonNull DartEntrypoint dartEntrypoint,
|
||||
@Nullable String initialRoute) {
|
||||
if (!isAttachedToJni()) {
|
||||
throw new IllegalStateException(
|
||||
"Spawn can only be called on a fully constructed FlutterEngine");
|
||||
@ -392,7 +394,9 @@ public class FlutterEngine {
|
||||
|
||||
FlutterJNI newFlutterJNI =
|
||||
flutterJNI.spawn(
|
||||
dartEntrypoint.dartEntrypointFunctionName, dartEntrypoint.dartEntrypointLibrary);
|
||||
dartEntrypoint.dartEntrypointFunctionName,
|
||||
dartEntrypoint.dartEntrypointLibrary,
|
||||
initialRoute);
|
||||
return new FlutterEngine(
|
||||
context, // Context.
|
||||
null, // FlutterLoader. A null value passed here causes the constructor to get it from the
|
||||
|
||||
@ -96,6 +96,27 @@ public class FlutterEngineGroup {
|
||||
*/
|
||||
public FlutterEngine createAndRunEngine(
|
||||
@NonNull Context context, @Nullable DartEntrypoint dartEntrypoint) {
|
||||
return createAndRunEngine(context, dartEntrypoint, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link io.flutter.embedding.engine.FlutterEngine} in this group and run its {@link
|
||||
* io.flutter.embedding.engine.dart.DartExecutor} with the specified {@link DartEntrypoint} and
|
||||
* the specified {@code initialRoute}.
|
||||
*
|
||||
* <p>If no prior {@link io.flutter.embedding.engine.FlutterEngine} were created in this group,
|
||||
* the initialization cost will be slightly higher than subsequent engines. The very first {@link
|
||||
* io.flutter.embedding.engine.FlutterEngine} created per program, regardless of
|
||||
* FlutterEngineGroup, also incurs the Dart VM creation time.
|
||||
*
|
||||
* <p>Subsequent engine creations will share resources with existing engines. However, if all
|
||||
* existing engines were {@link io.flutter.embedding.engine.FlutterEngine#destroy()}ed, the next
|
||||
* engine created will recreate its dependencies.
|
||||
*/
|
||||
public FlutterEngine createAndRunEngine(
|
||||
@NonNull Context context,
|
||||
@Nullable DartEntrypoint dartEntrypoint,
|
||||
@Nullable String initialRoute) {
|
||||
FlutterEngine engine = null;
|
||||
|
||||
if (dartEntrypoint == null) {
|
||||
@ -104,9 +125,12 @@ public class FlutterEngineGroup {
|
||||
|
||||
if (activeEngines.size() == 0) {
|
||||
engine = createEngine(context);
|
||||
if (initialRoute != null) {
|
||||
engine.getNavigationChannel().setInitialRoute(initialRoute);
|
||||
}
|
||||
engine.getDartExecutor().executeDartEntrypoint(dartEntrypoint);
|
||||
} else {
|
||||
engine = activeEngines.get(0).spawn(context, dartEntrypoint);
|
||||
engine = activeEngines.get(0).spawn(context, dartEntrypoint, initialRoute);
|
||||
}
|
||||
|
||||
activeEngines.add(engine);
|
||||
|
||||
@ -335,11 +335,14 @@ public class FlutterJNI {
|
||||
@UiThread
|
||||
@NonNull
|
||||
public FlutterJNI spawn(
|
||||
@Nullable String entrypointFunctionName, @Nullable String pathToEntrypointFunction) {
|
||||
@Nullable String entrypointFunctionName,
|
||||
@Nullable String pathToEntrypointFunction,
|
||||
@Nullable String initialRoute) {
|
||||
ensureRunningOnMainThread();
|
||||
ensureAttachedToNative();
|
||||
FlutterJNI spawnedJNI =
|
||||
nativeSpawn(nativeShellHolderId, entrypointFunctionName, pathToEntrypointFunction);
|
||||
nativeSpawn(
|
||||
nativeShellHolderId, entrypointFunctionName, pathToEntrypointFunction, initialRoute);
|
||||
Preconditions.checkState(
|
||||
spawnedJNI.nativeShellHolderId != null && spawnedJNI.nativeShellHolderId != 0,
|
||||
"Failed to spawn new JNI connected shell from existing shell.");
|
||||
@ -350,7 +353,8 @@ public class FlutterJNI {
|
||||
private native FlutterJNI nativeSpawn(
|
||||
long nativeSpawningShellId,
|
||||
@Nullable String entrypointFunctionName,
|
||||
@Nullable String pathToEntrypointFunction);
|
||||
@Nullable String pathToEntrypointFunction,
|
||||
@Nullable String initialRoute);
|
||||
|
||||
/**
|
||||
* Detaches this {@code FlutterJNI} instance from Flutter's native engine, which precludes any
|
||||
@ -359,7 +363,7 @@ public class FlutterJNI {
|
||||
* <p>This method must not be invoked if {@code FlutterJNI} is not already attached to native.
|
||||
*
|
||||
* <p>Invoking this method will result in the release of all native-side resources that were set
|
||||
* up during {@link #attachToNative()} or {@link #spawn(String, String)}, or accumulated
|
||||
* up during {@link #attachToNative()} or {@link #spawn(String, String, String)}, or accumulated
|
||||
* thereafter.
|
||||
*
|
||||
* <p>It is permissible to re-attach this instance to native after detaching it from native.
|
||||
|
||||
@ -154,7 +154,8 @@ static jobject SpawnJNI(JNIEnv* env,
|
||||
jobject jcaller,
|
||||
jlong shell_holder,
|
||||
jstring jEntrypoint,
|
||||
jstring jLibraryUrl) {
|
||||
jstring jLibraryUrl,
|
||||
jstring jInitialRoute) {
|
||||
jobject jni = env->NewObject(g_flutter_jni_class->obj(), g_jni_constructor);
|
||||
if (jni == nullptr) {
|
||||
FML_LOG(ERROR) << "Could not create a FlutterJNI instance";
|
||||
@ -167,9 +168,10 @@ static jobject SpawnJNI(JNIEnv* env,
|
||||
|
||||
auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint);
|
||||
auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl);
|
||||
auto initial_route = fml::jni::JavaStringToString(env, jInitialRoute);
|
||||
|
||||
auto spawned_shell_holder =
|
||||
ANDROID_SHELL_HOLDER->Spawn(jni_facade, entrypoint, libraryUrl);
|
||||
auto spawned_shell_holder = ANDROID_SHELL_HOLDER->Spawn(
|
||||
jni_facade, entrypoint, libraryUrl, initial_route);
|
||||
|
||||
if (spawned_shell_holder == nullptr || !spawned_shell_holder->IsValid()) {
|
||||
FML_LOG(ERROR) << "Could not spawn Shell";
|
||||
@ -620,7 +622,8 @@ bool RegisterApi(JNIEnv* env) {
|
||||
},
|
||||
{
|
||||
.name = "nativeSpawn",
|
||||
.signature = "(JLjava/lang/String;Ljava/lang/String;)Lio/flutter/"
|
||||
.signature = "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/"
|
||||
"String;)Lio/flutter/"
|
||||
"embedding/engine/FlutterJNI;",
|
||||
.fnPtr = reinterpret_cast<void*>(&SpawnJNI),
|
||||
},
|
||||
|
||||
@ -11,6 +11,7 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.isNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.nullable;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@ -21,6 +22,7 @@ import android.content.res.AssetManager;
|
||||
import io.flutter.FlutterInjector;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor.DartEntrypoint;
|
||||
import io.flutter.embedding.engine.loader.FlutterLoader;
|
||||
import io.flutter.embedding.engine.systemchannels.NavigationChannel;
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -119,7 +121,7 @@ public class FlutterEngineGroupComponentTest {
|
||||
|
||||
doReturn(mock(FlutterEngine.class))
|
||||
.when(firstEngine)
|
||||
.spawn(any(Context.class), any(DartEntrypoint.class));
|
||||
.spawn(any(Context.class), any(DartEntrypoint.class), nullable(String.class));
|
||||
|
||||
FlutterEngine secondEngine =
|
||||
engineGroupUnderTest.createAndRunEngine(
|
||||
@ -131,7 +133,7 @@ public class FlutterEngineGroupComponentTest {
|
||||
|
||||
// Now the second spawned engine is the only one left and it will be called to spawn the next
|
||||
// engine in the chain.
|
||||
when(secondEngine.spawn(any(Context.class), any(DartEntrypoint.class)))
|
||||
when(secondEngine.spawn(any(Context.class), any(DartEntrypoint.class), nullable(String.class)))
|
||||
.thenReturn(mock(FlutterEngine.class));
|
||||
|
||||
FlutterEngine thirdEngine =
|
||||
@ -156,4 +158,32 @@ public class FlutterEngineGroupComponentTest {
|
||||
isNull(String.class),
|
||||
any(AssetManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCreateAndRunWithCustomInitialRoute() {
|
||||
when(firstEngineUnderTest.getNavigationChannel()).thenReturn(mock(NavigationChannel.class));
|
||||
|
||||
FlutterEngine firstEngine =
|
||||
engineGroupUnderTest.createAndRunEngine(
|
||||
RuntimeEnvironment.application, mock(DartEntrypoint.class), "/foo");
|
||||
assertEquals(1, engineGroupUnderTest.activeEngines.size());
|
||||
verify(firstEngine.getNavigationChannel(), times(1)).setInitialRoute("/foo");
|
||||
|
||||
when(mockflutterJNI.isAttached()).thenReturn(true);
|
||||
jniAttached = false;
|
||||
FlutterJNI secondMockflutterJNI = mock(FlutterJNI.class);
|
||||
when(secondMockflutterJNI.isAttached()).thenAnswer(invocation -> jniAttached);
|
||||
doAnswer(invocation -> jniAttached = true).when(secondMockflutterJNI).attachToNative();
|
||||
doReturn(secondMockflutterJNI)
|
||||
.when(mockflutterJNI)
|
||||
.spawn(nullable(String.class), nullable(String.class), nullable(String.class));
|
||||
|
||||
FlutterEngine secondEngine =
|
||||
engineGroupUnderTest.createAndRunEngine(
|
||||
RuntimeEnvironment.application, mock(DartEntrypoint.class), "/bar");
|
||||
|
||||
assertEquals(2, engineGroupUnderTest.activeEngines.size());
|
||||
verify(mockflutterJNI, times(1))
|
||||
.spawn(nullable(String.class), nullable(String.class), eq("/bar"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,6 +225,27 @@ FLUTTER_DARWIN_EXPORT
|
||||
*/
|
||||
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint libraryURI:(nullable NSString*)uri;
|
||||
|
||||
/**
|
||||
* Runs a Dart program on an Isolate using the specified entrypoint and Dart library,
|
||||
* which may not be the same as the library containing the Dart program's `main()` function.
|
||||
*
|
||||
* The first call to this method will create a new Isolate. Subsequent calls will return
|
||||
* immediately and have no effect.
|
||||
*
|
||||
* @param entrypoint The name of a top-level function from a Dart library. If this is
|
||||
* FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's
|
||||
* main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the
|
||||
* method is not tree-shaken by the Dart compiler.
|
||||
* @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil,
|
||||
* this will default to the same library as the `main()` function in the Dart program.
|
||||
* @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is
|
||||
* FlutterDefaultInitialRoute (or nil), it will default to the "/" route.
|
||||
* @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise.
|
||||
*/
|
||||
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI
|
||||
initialRoute:(nullable NSString*)initialRoute;
|
||||
|
||||
/**
|
||||
* Destroy running context for an engine.
|
||||
*
|
||||
|
||||
@ -37,10 +37,35 @@ FLUTTER_DARWIN_EXPORT
|
||||
/**
|
||||
* Creates a running `FlutterEngine` that shares components with this group.
|
||||
*
|
||||
* @param entrypoint The name of a top-level function from a Dart library. If this is
|
||||
* FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's
|
||||
* main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the
|
||||
* method is not tree-shaken by the Dart compiler.
|
||||
* @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil,
|
||||
* this will default to the same library as the `main()` function in the Dart program.
|
||||
*
|
||||
* @see FlutterEngineGroup
|
||||
*/
|
||||
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI;
|
||||
|
||||
/**
|
||||
* Creates a running `FlutterEngine` that shares components with this group.
|
||||
*
|
||||
* @param entrypoint The name of a top-level function from a Dart library. If this is
|
||||
* FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's
|
||||
* main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the
|
||||
* method is not tree-shaken by the Dart compiler.
|
||||
* @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil,
|
||||
* this will default to the same library as the `main()` function in the Dart program.
|
||||
* @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is
|
||||
* FlutterDefaultInitialRoute (or nil), it will default to the "/" route.
|
||||
*
|
||||
* @see FlutterEngineGroup
|
||||
*/
|
||||
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI
|
||||
initialRoute:(nullable NSString*)initialRoute;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -998,7 +998,8 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
|
||||
}
|
||||
|
||||
- (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
|
||||
libraryURI:(/*nullable*/ NSString*)libraryURI {
|
||||
libraryURI:(/*nullable*/ NSString*)libraryURI
|
||||
initialRoute:(/*nullable*/ NSString*)initialRoute {
|
||||
NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
|
||||
FlutterEngine* result = [[FlutterEngine alloc] initWithName:_labelPrefix
|
||||
project:_dartProject.get()
|
||||
@ -1027,8 +1028,13 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
|
||||
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
|
||||
[](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
|
||||
|
||||
std::unique_ptr<flutter::Shell> shell =
|
||||
_shell->Spawn(std::move(configuration), on_create_platform_view, on_create_rasterizer);
|
||||
std::string cppInitialRoute;
|
||||
if (initialRoute) {
|
||||
cppInitialRoute = [initialRoute UTF8String];
|
||||
}
|
||||
|
||||
std::unique_ptr<flutter::Shell> shell = _shell->Spawn(
|
||||
std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
|
||||
|
||||
result->_threadHost = _threadHost;
|
||||
result->_profiler = _profiler;
|
||||
|
||||
@ -35,14 +35,22 @@
|
||||
|
||||
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI {
|
||||
return [self makeEngineWithEntrypoint:entrypoint libraryURI:libraryURI initialRoute:nil];
|
||||
}
|
||||
|
||||
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI
|
||||
initialRoute:(nullable NSString*)initialRoute {
|
||||
NSString* engineName = [NSString stringWithFormat:@"%@.%d", self.name, ++_enginesCreatedCount];
|
||||
FlutterEngine* engine;
|
||||
if (self.engines.count <= 0) {
|
||||
engine = [[FlutterEngine alloc] initWithName:engineName project:self.project];
|
||||
[engine runWithEntrypoint:entrypoint libraryURI:libraryURI];
|
||||
[engine runWithEntrypoint:entrypoint libraryURI:libraryURI initialRoute:initialRoute];
|
||||
} else {
|
||||
FlutterEngine* spawner = (FlutterEngine*)[self.engines[0] pointerValue];
|
||||
engine = [spawner spawnWithEntrypoint:entrypoint libraryURI:libraryURI];
|
||||
engine = [spawner spawnWithEntrypoint:entrypoint
|
||||
libraryURI:libraryURI
|
||||
initialRoute:initialRoute];
|
||||
}
|
||||
[_engines addObject:[NSValue valueWithPointer:engine]];
|
||||
|
||||
|
||||
@ -194,7 +194,7 @@ FLUTTER_ASSERT_ARC
|
||||
- (void)testSpawn {
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
|
||||
[engine run];
|
||||
FlutterEngine* spawn = [engine spawnWithEntrypoint:nil libraryURI:nil];
|
||||
FlutterEngine* spawn = [engine spawnWithEntrypoint:nil libraryURI:nil initialRoute:nil];
|
||||
XCTAssertNotNil(spawn);
|
||||
}
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ FLUTTER_ASSERT_NOT_ARC
|
||||
- (void)testSpawnsShareGpuContext {
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
|
||||
[engine run];
|
||||
FlutterEngine* spawn = [engine spawnWithEntrypoint:nil libraryURI:nil];
|
||||
FlutterEngine* spawn = [engine spawnWithEntrypoint:nil libraryURI:nil initialRoute:nil];
|
||||
XCTAssertNotNil(spawn);
|
||||
XCTAssertTrue([engine iosPlatformView] != nullptr);
|
||||
XCTAssertTrue([spawn iosPlatformView] != nullptr);
|
||||
|
||||
@ -67,7 +67,8 @@ extern NSString* _Nonnull const FlutterEngineWillDealloc;
|
||||
* This should only be called on a FlutterEngine that is running.
|
||||
*/
|
||||
- (nonnull FlutterEngine*)spawnWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI;
|
||||
libraryURI:(nullable NSString*)libraryURI
|
||||
initialRoute:(nullable NSString*)initialRoute;
|
||||
|
||||
/**
|
||||
* Dispatches the given key event data to the framework through the engine.
|
||||
|
||||
@ -19,6 +19,7 @@ class ThreadHost;
|
||||
- (flutter::IOSRenderingAPI)platformViewsRenderingAPI;
|
||||
- (void)waitForFirstFrame:(NSTimeInterval)timeout callback:(void (^)(BOOL didTimeout))callback;
|
||||
- (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
|
||||
libraryURI:(/*nullable*/ NSString*)libraryURI;
|
||||
libraryURI:(/*nullable*/ NSString*)libraryURI
|
||||
initialRoute:(/*nullable*/ NSString*)initialRoute;
|
||||
- (const flutter::ThreadHost&)threadHost;
|
||||
@end
|
||||
|
||||
@ -91,7 +91,7 @@
|
||||
FlutterEngine* spawner = [[FlutterEngine alloc] initWithName:@"FlutterControllerTest"
|
||||
project:nil];
|
||||
[spawner run];
|
||||
return [spawner spawnWithEntrypoint:nil libraryURI:nil];
|
||||
return [spawner spawnWithEntrypoint:nil libraryURI:nil initialRoute:nil];
|
||||
} else {
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"FlutterControllerTest"
|
||||
project:nil];
|
||||
|
||||
@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (instancetype)initWithScenario:(NSString*)scenario
|
||||
withCompletion:(nullable void (^)(void))engineRunCompletion;
|
||||
- (FlutterEngine*)spawnWithEntrypoint:(nullable NSString*)entrypoint
|
||||
libraryURI:(nullable NSString*)libraryURI;
|
||||
libraryURI:(nullable NSString*)libraryURI
|
||||
initialRoute:(nullable NSString*)initialRoute;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user