diff --git a/shell/platform/windows/client_wrapper/flutter_engine.cc b/shell/platform/windows/client_wrapper/flutter_engine.cc index f6073f7f849de..a1fc0c4659066 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine.cc @@ -17,6 +17,19 @@ FlutterEngine::FlutterEngine(const DartProject& project) { c_engine_properties.icu_data_path = project.icu_data_path().c_str(); c_engine_properties.aot_library_path = project.aot_library_path().c_str(); + const std::vector& entrypoint_args = + project.dart_entrypoint_arguments(); + std::vector entrypoint_argv; + std::transform( + entrypoint_args.begin(), entrypoint_args.end(), + std::back_inserter(entrypoint_argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); + + c_engine_properties.dart_entrypoint_argc = + static_cast(entrypoint_argv.size()); + c_engine_properties.dart_entrypoint_argv = + entrypoint_argv.size() > 0 ? entrypoint_argv.data() : nullptr; + engine_ = FlutterDesktopEngineCreate(c_engine_properties); auto core_messenger = FlutterDesktopEngineGetMessenger(engine_); diff --git a/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc b/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc index 8fc43b7402db3..e52fb336a3373 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc @@ -20,6 +20,14 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi { FlutterDesktopEngineRef EngineCreate( const FlutterDesktopEngineProperties& engine_properties) { create_called_ = true; + + // dart_entrypoint_argv is only guaranteed to exist until this method + // returns, so copy it here for unit test validation + dart_entrypoint_arguments_.clear(); + for (int i = 0; i < engine_properties.dart_entrypoint_argc; i++) { + dart_entrypoint_arguments_.push_back( + std::string(engine_properties.dart_entrypoint_argv[i])); + } return reinterpret_cast(1); } @@ -49,11 +57,16 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi { bool reload_fonts_called() { return reload_fonts_called_; } + const std::vector& dart_entrypoint_arguments() { + return dart_entrypoint_arguments_; + } + private: bool create_called_ = false; bool run_called_ = false; bool destroy_called_ = false; bool reload_fonts_called_ = false; + std::vector dart_entrypoint_arguments_; }; } // namespace @@ -121,4 +134,21 @@ TEST(FlutterEngineTest, GetMessenger) { EXPECT_NE(engine.messenger(), nullptr); } +TEST(FlutterEngineTest, DartEntrypointArgs) { + testing::ScopedStubFlutterWindowsApi scoped_api_stub( + std::make_unique()); + auto test_api = static_cast(scoped_api_stub.stub()); + + DartProject project(L"data"); + std::vector arguments = {"one", "two"}; + project.set_dart_entrypoint_arguments(arguments); + + FlutterEngine engine(project); + const std::vector& arguments_ref = + test_api->dart_entrypoint_arguments(); + ASSERT_EQ(2, arguments_ref.size()); + EXPECT_TRUE(arguments[0] == arguments_ref[0]); + EXPECT_TRUE(arguments[1] == arguments_ref[1]); +} + } // namespace flutter diff --git a/shell/platform/windows/client_wrapper/include/flutter/dart_project.h b/shell/platform/windows/client_wrapper/include/flutter/dart_project.h index 9f064417bf028..9dff236ff2cd5 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/dart_project.h +++ b/shell/platform/windows/client_wrapper/include/flutter/dart_project.h @@ -29,6 +29,18 @@ class DartProject { ~DartProject() = default; + // Sets the command line arguments that should be passed to the Dart + // entrypoint. + void set_dart_entrypoint_arguments(std::vector arguments) { + dart_entrypoint_arguments_ = std::move(arguments); + } + + // Returns any command line arguments that should be passed to the Dart + // entrypoint. + const std::vector& dart_entrypoint_arguments() const { + return dart_entrypoint_arguments_; + } + private: // Accessors for internals are private, so that they can be changed if more // flexible options for project structures are needed later without it @@ -49,6 +61,8 @@ class DartProject { // The path to the AOT library. This will always return a path, but non-AOT // builds will not be expected to actually have a library at that path. std::wstring aot_library_path_; + // The list of arguments to pass through to the Dart entrypoint. + std::vector dart_entrypoint_arguments_; }; } // namespace flutter diff --git a/shell/platform/windows/flutter_project_bundle.cc b/shell/platform/windows/flutter_project_bundle.cc index 4b2c8dfef69be..4790697b585e8 100644 --- a/shell/platform/windows/flutter_project_bundle.cc +++ b/shell/platform/windows/flutter_project_bundle.cc @@ -20,6 +20,11 @@ FlutterProjectBundle::FlutterProjectBundle( aot_library_path_ = std::filesystem::path(properties.aot_library_path); } + for (int i = 0; i < properties.dart_entrypoint_argc; i++) { + dart_entrypoint_arguments_.push_back( + std::string(properties.dart_entrypoint_argv[i])); + } + // Resolve any relative paths. if (assets_path_.is_relative() || icu_path_.is_relative() || (!aot_library_path_.empty() && aot_library_path_.is_relative())) { diff --git a/shell/platform/windows/flutter_project_bundle.h b/shell/platform/windows/flutter_project_bundle.h index fc77adfe8c00b..72ee38d12fdb8 100644 --- a/shell/platform/windows/flutter_project_bundle.h +++ b/shell/platform/windows/flutter_project_bundle.h @@ -51,12 +51,21 @@ class FlutterProjectBundle { // Logs and returns nullptr on failure. UniqueAotDataPtr LoadAotData(); + // Returns the command line arguments to be passed through to the Dart + // entrypoint. + const std::vector& dart_entrypoint_arguments() const { + return dart_entrypoint_arguments_; + } + private: std::filesystem::path assets_path_; std::filesystem::path icu_path_; // Path to the AOT library file, if any. std::filesystem::path aot_library_path_; + + // Dart entrypoint arguments. + std::vector dart_entrypoint_arguments_; }; } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index d70ca504c1b56..7516c6a5af0c4 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -143,6 +143,14 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { switches.begin(), switches.end(), std::back_inserter(argv), [](const std::string& arg) -> const char* { return arg.c_str(); }); + const std::vector& entrypoint_args = + project_->dart_entrypoint_arguments(); + std::vector entrypoint_argv; + std::transform( + entrypoint_args.begin(), entrypoint_args.end(), + std::back_inserter(entrypoint_argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); + // Configure task runners. FlutterTaskRunnerDescription platform_task_runner = {}; platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); @@ -166,6 +174,9 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { args.icu_data_path = icu_path_string.c_str(); args.command_line_argc = static_cast(argv.size()); args.command_line_argv = argv.size() > 0 ? argv.data() : nullptr; + args.dart_entrypoint_argc = static_cast(entrypoint_argv.size()); + args.dart_entrypoint_argv = + entrypoint_argv.size() > 0 ? entrypoint_argv.data() : nullptr; args.platform_message_callback = [](const FlutterPlatformMessage* engine_message, void* user_data) -> void { diff --git a/shell/platform/windows/public/flutter_windows.h b/shell/platform/windows/public/flutter_windows.h index 25414937e54f6..2c53e1740df52 100644 --- a/shell/platform/windows/public/flutter_windows.h +++ b/shell/platform/windows/public/flutter_windows.h @@ -46,6 +46,13 @@ typedef struct { // containing the executable. This can be nullptr for a non-AOT build, as // it will be ignored in that case. const wchar_t* aot_library_path; + + // Number of elements in the array passed in as dart_entrypoint_argv. + int dart_entrypoint_argc; + + // Array of Dart entrypoint arguments. This is deep copied during the call + // to FlutterDesktopEngineCreate. + const char** dart_entrypoint_argv; } FlutterDesktopEngineProperties; // ========== View Controller ==========