diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 971ef22024f59..06b45ac5372e1 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -1126,6 +1126,20 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, } } + if (SAFE_ACCESS(args, dart_entrypoint_argc, 0) > 0) { + if (SAFE_ACCESS(args, dart_entrypoint_argv, nullptr) == nullptr) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Could not determine Dart entrypoint arguments " + "as dart_entrypoint_argc " + "was set, but dart_entrypoint_argv was null."); + } + std::vector arguments(args->dart_entrypoint_argc); + for (int i = 0; i < args->dart_entrypoint_argc; ++i) { + arguments[i] = std::string{args->dart_entrypoint_argv[i]}; + } + settings.dart_entrypoint_args = std::move(arguments); + } + if (!run_configuration.IsValid()) { return LOG_EMBEDDER_ERROR( kInvalidArguments, diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 8ed2dadfac37f..51d832bfe5397 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1368,6 +1368,19 @@ typedef struct { /// matches what the platform would natively resolve to as possible. FlutterComputePlatformResolvedLocaleCallback compute_platform_resolved_locale_callback; + + /// The command line argument count for arguments passed through to the Dart + /// entrypoint. + int dart_entrypoint_argc; + + /// The command line arguments passed through to the Dart entrypoint. The + /// strings must be `NULL` terminated. + /// + /// The strings will be copied out and so any strings passed in here can + /// be safely collected after initializing the engine with + /// `FlutterProjectArgs`. + const char* const* dart_entrypoint_argv; + } FlutterProjectArgs; //------------------------------------------------------------------------------ diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index de4cf422b662f..5dae4e494745c 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -733,3 +733,10 @@ void render_targets_are_recycled() { }; window.scheduleFrame(); } + +void nativeArgumentsCallback(List args) native 'NativeArgumentsCallback'; + +@pragma('vm:entry-point') +void dart_entrypoint_args(List args) { + nativeArgumentsCallback(args); +} diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index 5c1f741996257..93d4c6af916f2 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -217,6 +217,14 @@ void EmbedderConfigBuilder::AddCommandLineArgument(std::string arg) { command_line_arguments_.emplace_back(std::move(arg)); } +void EmbedderConfigBuilder::AddDartEntrypointArgument(std::string arg) { + if (arg.size() == 0) { + return; + } + + dart_entrypoint_arguments_.emplace_back(std::move(arg)); +} + void EmbedderConfigBuilder::SetPlatformTaskRunner( const FlutterTaskRunnerDescription* runner) { if (runner == nullptr) { @@ -317,6 +325,23 @@ UniqueEngine EmbedderConfigBuilder::SetupEngine(bool run) const { project_args.command_line_argc = 0; } + std::vector dart_args; + dart_args.reserve(dart_entrypoint_arguments_.size()); + + for (const auto& arg : dart_entrypoint_arguments_) { + dart_args.push_back(arg.c_str()); + } + + if (dart_args.size() > 0) { + project_args.dart_entrypoint_argv = dart_args.data(); + project_args.dart_entrypoint_argc = dart_args.size(); + } else { + // Clear it out in case this is not the first engine launch from the + // embedder config builder. + project_args.dart_entrypoint_argv = nullptr; + project_args.dart_entrypoint_argc = 0; + } + auto result = run ? FlutterEngineRun(FLUTTER_ENGINE_VERSION, &renderer_config_, &project_args, &context_, &engine) diff --git a/shell/platform/embedder/tests/embedder_config_builder.h b/shell/platform/embedder/tests/embedder_config_builder.h index 29dc4ef65ad11..4c37d644bc7ac 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.h +++ b/shell/platform/embedder/tests/embedder_config_builder.h @@ -76,6 +76,8 @@ class EmbedderConfigBuilder { void AddCommandLineArgument(std::string arg); + void AddDartEntrypointArgument(std::string arg); + void SetPlatformTaskRunner(const FlutterTaskRunnerDescription* runner); void SetRenderTaskRunner(const FlutterTaskRunnerDescription* runner); @@ -106,6 +108,7 @@ class EmbedderConfigBuilder { FlutterCustomTaskRunners custom_task_runners_ = {}; FlutterCompositor compositor_ = {}; std::vector command_line_arguments_; + std::vector dart_entrypoint_arguments_; UniqueEngine SetupEngine(bool run) const; diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 786b7da063e9f..01309bb7366f3 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -473,6 +473,33 @@ TEST_F(EmbedderTest, VMShutsDownWhenNoEnginesInProcess) { } } +//------------------------------------------------------------------------------ +/// +TEST_F(EmbedderTest, DartEntrypointArgs) { + auto& context = GetEmbedderContext(ContextType::kSoftwareContext); + EmbedderConfigBuilder builder(context); + builder.SetSoftwareRendererConfig(); + builder.AddDartEntrypointArgument("foo"); + builder.AddDartEntrypointArgument("bar"); + builder.SetDartEntrypoint("dart_entrypoint_args"); + fml::AutoResetWaitableEvent callback_latch; + std::vector callback_args; + auto nativeArgumentsCallback = [&callback_args, + &callback_latch](Dart_NativeArguments args) { + Dart_Handle exception = nullptr; + callback_args = + tonic::DartConverter>::FromArguments( + args, 0, exception); + callback_latch.Signal(); + }; + context.AddNativeCallback("NativeArgumentsCallback", + CREATE_NATIVE_ENTRY(nativeArgumentsCallback)); + auto engine = builder.LaunchEngine(); + callback_latch.Wait(); + ASSERT_EQ(callback_args[0], "foo"); + ASSERT_EQ(callback_args[1], "bar"); +} + //------------------------------------------------------------------------------ /// These snapshots may be materialized from symbols and the size field may not /// be relevant. Since this information is redundant, engine launch should not