@@ -1979,6 +1979,381 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
19791979 return kSuccess ;
19801980}
19811981
1982+ FlutterEngineResult FlutterEngineSpawn (size_t version,
1983+ const FlutterRendererConfig* config,
1984+ const FlutterProjectArgs* args,
1985+ void * user_data,
1986+ FLUTTER_API_SYMBOL (FlutterEngine)
1987+ engine_spawner,
1988+ FLUTTER_API_SYMBOL(FlutterEngine) *
1989+ engine_out) {
1990+ // Step 0. Figure out arguments for shell spawn.
1991+ if (version != FLUTTER_ENGINE_VERSION) {
1992+ return LOG_EMBEDDER_ERROR (
1993+ kInvalidLibraryVersion ,
1994+ " Flutter embedder version mismatch. There has been a breaking change. "
1995+ " Please consult the changelog and update the embedder." );
1996+ }
1997+
1998+ if (engine_out == nullptr ) {
1999+ return LOG_EMBEDDER_ERROR (kInvalidArguments ,
2000+ " The engine out parameter was missing." );
2001+ }
2002+
2003+ if (args == nullptr ) {
2004+ return LOG_EMBEDDER_ERROR (kInvalidArguments ,
2005+ " The Flutter project arguments were missing." );
2006+ }
2007+
2008+ if (SAFE_ACCESS (args, assets_path, nullptr ) == nullptr ) {
2009+ return LOG_EMBEDDER_ERROR (
2010+ kInvalidArguments ,
2011+ " The assets path in the Flutter project arguments was missing." );
2012+ }
2013+
2014+ if (SAFE_ACCESS (args, main_path__unused__, nullptr ) != nullptr ) {
2015+ FML_LOG (WARNING)
2016+ << " FlutterProjectArgs.main_path is deprecated and should be set null." ;
2017+ }
2018+
2019+ if (SAFE_ACCESS (args, packages_path__unused__, nullptr ) != nullptr ) {
2020+ FML_LOG (WARNING) << " FlutterProjectArgs.packages_path is deprecated and "
2021+ " should be set null." ;
2022+ }
2023+
2024+ if (!IsRendererValid (config)) {
2025+ return LOG_EMBEDDER_ERROR (kInvalidArguments ,
2026+ " The renderer configuration was invalid." );
2027+ }
2028+
2029+ std::string icu_data_path;
2030+ if (SAFE_ACCESS (args, icu_data_path, nullptr ) != nullptr ) {
2031+ icu_data_path = SAFE_ACCESS (args, icu_data_path, nullptr );
2032+ }
2033+
2034+ if (SAFE_ACCESS (args, persistent_cache_path, nullptr ) != nullptr ) {
2035+ std::string persistent_cache_path =
2036+ SAFE_ACCESS (args, persistent_cache_path, nullptr );
2037+ flutter::PersistentCache::SetCacheDirectoryPath (persistent_cache_path);
2038+ }
2039+
2040+ if (SAFE_ACCESS (args, is_persistent_cache_read_only, false )) {
2041+ flutter::PersistentCache::gIsReadOnly = true ;
2042+ }
2043+
2044+ fml::CommandLine command_line;
2045+ if (SAFE_ACCESS (args, command_line_argc, 0 ) != 0 &&
2046+ SAFE_ACCESS (args, command_line_argv, nullptr ) != nullptr ) {
2047+ command_line = fml::CommandLineFromArgcArgv (
2048+ SAFE_ACCESS (args, command_line_argc, 0 ),
2049+ SAFE_ACCESS (args, command_line_argv, nullptr ));
2050+ }
2051+
2052+ flutter::Settings settings = flutter::SettingsFromCommandLine (command_line);
2053+
2054+ if (SAFE_ACCESS (args, aot_data, nullptr )) {
2055+ if (SAFE_ACCESS (args, vm_snapshot_data, nullptr ) ||
2056+ SAFE_ACCESS (args, vm_snapshot_instructions, nullptr ) ||
2057+ SAFE_ACCESS (args, isolate_snapshot_data, nullptr ) ||
2058+ SAFE_ACCESS (args, isolate_snapshot_instructions, nullptr )) {
2059+ return LOG_EMBEDDER_ERROR (
2060+ kInvalidArguments ,
2061+ " Multiple AOT sources specified. Embedders should provide either "
2062+ " *_snapshot_* buffers or aot_data, not both." );
2063+ }
2064+ }
2065+
2066+ if (flutter::DartVM::IsRunningPrecompiledCode ()) {
2067+ PopulateAOTSnapshotMappingCallbacks (args, settings);
2068+ } else {
2069+ PopulateJITSnapshotMappingCallbacks (args, settings);
2070+ }
2071+
2072+ settings.icu_data_path = icu_data_path;
2073+ settings.assets_path = args->assets_path ;
2074+ settings.leak_vm = !SAFE_ACCESS (args, shutdown_dart_vm_when_done, false );
2075+ settings.old_gen_heap_size = SAFE_ACCESS (args, dart_old_gen_heap_size, -1 );
2076+
2077+ if (!flutter::DartVM::IsRunningPrecompiledCode ()) {
2078+ // Verify the assets path contains Dart 2 kernel assets.
2079+ const std::string kApplicationKernelSnapshotFileName = " kernel_blob.bin" ;
2080+ std::string application_kernel_path = fml::paths::JoinPaths (
2081+ {settings.assets_path , kApplicationKernelSnapshotFileName });
2082+ if (!fml::IsFile (application_kernel_path)) {
2083+ return LOG_EMBEDDER_ERROR (
2084+ kInvalidArguments ,
2085+ " Not running in AOT mode but could not resolve the kernel binary." );
2086+ }
2087+ settings.application_kernel_asset = kApplicationKernelSnapshotFileName ;
2088+ }
2089+
2090+ settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
2091+ fml::MessageLoop::GetCurrent ().AddTaskObserver (key, callback);
2092+ };
2093+ settings.task_observer_remove = [](intptr_t key) {
2094+ fml::MessageLoop::GetCurrent ().RemoveTaskObserver (key);
2095+ };
2096+ if (SAFE_ACCESS (args, root_isolate_create_callback, nullptr ) != nullptr ) {
2097+ VoidCallback callback =
2098+ SAFE_ACCESS (args, root_isolate_create_callback, nullptr );
2099+ settings.root_isolate_create_callback =
2100+ [callback, user_data](const auto & isolate) { callback (user_data); };
2101+ }
2102+ if (SAFE_ACCESS (args, log_message_callback, nullptr ) != nullptr ) {
2103+ FlutterLogMessageCallback callback =
2104+ SAFE_ACCESS (args, log_message_callback, nullptr );
2105+ settings.log_message_callback = [callback, user_data](
2106+ const std::string& tag,
2107+ const std::string& message) {
2108+ callback (tag.c_str (), message.c_str (), user_data);
2109+ };
2110+ }
2111+ if (SAFE_ACCESS (args, log_tag, nullptr ) != nullptr ) {
2112+ settings.log_tag = SAFE_ACCESS (args, log_tag, nullptr );
2113+ }
2114+
2115+ bool has_update_semantics_2_callback =
2116+ SAFE_ACCESS (args, update_semantics_callback2, nullptr ) != nullptr ;
2117+ bool has_update_semantics_callback =
2118+ SAFE_ACCESS (args, update_semantics_callback, nullptr ) != nullptr ;
2119+ bool has_legacy_update_semantics_callback =
2120+ SAFE_ACCESS (args, update_semantics_node_callback, nullptr ) != nullptr ||
2121+ SAFE_ACCESS (args, update_semantics_custom_action_callback, nullptr ) !=
2122+ nullptr ;
2123+
2124+ int semantic_callback_count = (has_update_semantics_2_callback ? 1 : 0 ) +
2125+ (has_update_semantics_callback ? 1 : 0 ) +
2126+ (has_legacy_update_semantics_callback ? 1 : 0 );
2127+
2128+ if (semantic_callback_count > 1 ) {
2129+ return LOG_EMBEDDER_ERROR (
2130+ kInvalidArguments ,
2131+ " Multiple semantics update callbacks provided. "
2132+ " Embedders should provide either `update_semantics_callback2`, "
2133+ " `update_semantics_callback`, or both "
2134+ " `update_semantics_node_callback` and "
2135+ " `update_semantics_custom_action_callback`." );
2136+ }
2137+
2138+ flutter::PlatformViewEmbedder::UpdateSemanticsCallback
2139+ update_semantics_callback =
2140+ CreateEmbedderSemanticsUpdateCallback (args, user_data);
2141+
2142+ flutter::PlatformViewEmbedder::PlatformMessageResponseCallback
2143+ platform_message_response_callback = nullptr ;
2144+ if (SAFE_ACCESS (args, platform_message_callback, nullptr ) != nullptr ) {
2145+ platform_message_response_callback =
2146+ [ptr = args->platform_message_callback ,
2147+ user_data](std::unique_ptr<flutter::PlatformMessage> message) {
2148+ auto handle = new FlutterPlatformMessageResponseHandle ();
2149+ const FlutterPlatformMessage incoming_message = {
2150+ sizeof (FlutterPlatformMessage), // struct_size
2151+ message->channel ().c_str (), // channel
2152+ message->data ().GetMapping (), // message
2153+ message->data ().GetSize (), // message_size
2154+ handle, // response_handle
2155+ };
2156+ handle->message = std::move (message);
2157+ return ptr (&incoming_message, user_data);
2158+ };
2159+ }
2160+
2161+ flutter::VsyncWaiterEmbedder::VsyncCallback vsync_callback = nullptr ;
2162+ if (SAFE_ACCESS (args, vsync_callback, nullptr ) != nullptr ) {
2163+ vsync_callback = [ptr = args->vsync_callback , user_data](intptr_t baton) {
2164+ return ptr (user_data, baton);
2165+ };
2166+ }
2167+
2168+ flutter::PlatformViewEmbedder::ComputePlatformResolvedLocaleCallback
2169+ compute_platform_resolved_locale_callback = nullptr ;
2170+ if (SAFE_ACCESS (args, compute_platform_resolved_locale_callback, nullptr ) !=
2171+ nullptr ) {
2172+ compute_platform_resolved_locale_callback =
2173+ [ptr = args->compute_platform_resolved_locale_callback ](
2174+ const std::vector<std::string>& supported_locales_data) {
2175+ const size_t number_of_strings_per_locale = 3 ;
2176+ size_t locale_count =
2177+ supported_locales_data.size () / number_of_strings_per_locale;
2178+ std::vector<FlutterLocale> supported_locales;
2179+ std::vector<const FlutterLocale*> supported_locales_ptr;
2180+ for (size_t i = 0 ; i < locale_count; ++i) {
2181+ supported_locales.push_back (
2182+ {.struct_size = sizeof (FlutterLocale),
2183+ .language_code =
2184+ supported_locales_data[i * number_of_strings_per_locale +
2185+ 0 ]
2186+ .c_str (),
2187+ .country_code =
2188+ supported_locales_data[i * number_of_strings_per_locale +
2189+ 1 ]
2190+ .c_str (),
2191+ .script_code =
2192+ supported_locales_data[i * number_of_strings_per_locale +
2193+ 2 ]
2194+ .c_str (),
2195+ .variant_code = nullptr });
2196+ supported_locales_ptr.push_back (&supported_locales[i]);
2197+ }
2198+
2199+ const FlutterLocale* result =
2200+ ptr (supported_locales_ptr.data (), locale_count);
2201+
2202+ std::unique_ptr<std::vector<std::string>> out =
2203+ std::make_unique<std::vector<std::string>>();
2204+ if (result) {
2205+ std::string language_code (SAFE_ACCESS (result, language_code, " " ));
2206+ if (language_code != " " ) {
2207+ out->push_back (language_code);
2208+ out->emplace_back (SAFE_ACCESS (result, country_code, " " ));
2209+ out->emplace_back (SAFE_ACCESS (result, script_code, " " ));
2210+ }
2211+ }
2212+ return out;
2213+ };
2214+ }
2215+
2216+ flutter::PlatformViewEmbedder::OnPreEngineRestartCallback
2217+ on_pre_engine_restart_callback = nullptr ;
2218+ if (SAFE_ACCESS (args, on_pre_engine_restart_callback, nullptr ) != nullptr ) {
2219+ on_pre_engine_restart_callback = [ptr =
2220+ args->on_pre_engine_restart_callback ,
2221+ user_data]() { return ptr (user_data); };
2222+ }
2223+
2224+ auto external_view_embedder_result =
2225+ InferExternalViewEmbedderFromArgs (SAFE_ACCESS (args, compositor, nullptr ));
2226+ if (external_view_embedder_result.second ) {
2227+ return LOG_EMBEDDER_ERROR (kInvalidArguments ,
2228+ " Compositor arguments were invalid." );
2229+ }
2230+
2231+ flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
2232+ {
2233+ update_semantics_callback, //
2234+ platform_message_response_callback, //
2235+ vsync_callback, //
2236+ compute_platform_resolved_locale_callback, //
2237+ on_pre_engine_restart_callback, //
2238+ };
2239+
2240+ auto on_create_platform_view = InferPlatformViewCreationCallback (
2241+ config, user_data, platform_dispatch_table,
2242+ std::move (external_view_embedder_result.first ));
2243+
2244+ if (!on_create_platform_view) {
2245+ return LOG_EMBEDDER_ERROR (
2246+ kInternalInconsistency ,
2247+ " Could not infer platform view creation callback." );
2248+ }
2249+
2250+ flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
2251+ [](flutter::Shell& shell) {
2252+ return std::make_unique<flutter::Rasterizer>(shell);
2253+ };
2254+
2255+ using ExternalTextureResolver = flutter::EmbedderExternalTextureResolver;
2256+ std::unique_ptr<ExternalTextureResolver> external_texture_resolver;
2257+ external_texture_resolver = std::make_unique<ExternalTextureResolver>();
2258+
2259+ #ifdef SHELL_ENABLE_GL
2260+ flutter::EmbedderExternalTextureGL::ExternalTextureCallback
2261+ external_texture_callback;
2262+ if (config->type == kOpenGL ) {
2263+ const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl ;
2264+ if (SAFE_ACCESS (open_gl_config, gl_external_texture_frame_callback,
2265+ nullptr ) != nullptr ) {
2266+ external_texture_callback =
2267+ [ptr = open_gl_config->gl_external_texture_frame_callback , user_data](
2268+ int64_t texture_identifier, size_t width,
2269+ size_t height) -> std::unique_ptr<FlutterOpenGLTexture> {
2270+ std::unique_ptr<FlutterOpenGLTexture> texture =
2271+ std::make_unique<FlutterOpenGLTexture>();
2272+ if (!ptr (user_data, texture_identifier, width, height, texture.get ())) {
2273+ return nullptr ;
2274+ }
2275+ return texture;
2276+ };
2277+ external_texture_resolver =
2278+ std::make_unique<ExternalTextureResolver>(external_texture_callback);
2279+ }
2280+ }
2281+ #endif
2282+ #ifdef SHELL_ENABLE_METAL
2283+ flutter::EmbedderExternalTextureMetal::ExternalTextureCallback
2284+ external_texture_metal_callback;
2285+ if (config->type == kMetal ) {
2286+ const FlutterMetalRendererConfig* metal_config = &config->metal ;
2287+ if (SAFE_ACCESS (metal_config, external_texture_frame_callback, nullptr )) {
2288+ external_texture_metal_callback =
2289+ [ptr = metal_config->external_texture_frame_callback , user_data](
2290+ int64_t texture_identifier, size_t width,
2291+ size_t height) -> std::unique_ptr<FlutterMetalExternalTexture> {
2292+ std::unique_ptr<FlutterMetalExternalTexture> texture =
2293+ std::make_unique<FlutterMetalExternalTexture>();
2294+ texture->struct_size = sizeof (FlutterMetalExternalTexture);
2295+ if (!ptr (user_data, texture_identifier, width, height, texture.get ())) {
2296+ return nullptr ;
2297+ }
2298+ return texture;
2299+ };
2300+ external_texture_resolver = std::make_unique<ExternalTextureResolver>(
2301+ external_texture_metal_callback);
2302+ }
2303+ }
2304+ #endif
2305+
2306+ auto run_configuration =
2307+ flutter::RunConfiguration::InferFromSettings (settings);
2308+
2309+ if (SAFE_ACCESS (args, custom_dart_entrypoint, nullptr ) != nullptr ) {
2310+ auto dart_entrypoint = std::string{args->custom_dart_entrypoint };
2311+ if (!dart_entrypoint.empty ()) {
2312+ run_configuration.SetEntrypoint (std::move (dart_entrypoint));
2313+ }
2314+ }
2315+
2316+ if (SAFE_ACCESS (args, dart_entrypoint_argc, 0 ) > 0 ) {
2317+ if (SAFE_ACCESS (args, dart_entrypoint_argv, nullptr ) == nullptr ) {
2318+ return LOG_EMBEDDER_ERROR (kInvalidArguments ,
2319+ " Could not determine Dart entrypoint arguments "
2320+ " as dart_entrypoint_argc "
2321+ " was set, but dart_entrypoint_argv was null." );
2322+ }
2323+ std::vector<std::string> arguments (args->dart_entrypoint_argc );
2324+ for (int i = 0 ; i < args->dart_entrypoint_argc ; ++i) {
2325+ arguments[i] = std::string{args->dart_entrypoint_argv [i]};
2326+ }
2327+ run_configuration.SetEntrypointArgs (std::move (arguments));
2328+ }
2329+
2330+ if (!run_configuration.IsValid ()) {
2331+ return LOG_EMBEDDER_ERROR (
2332+ kInvalidArguments ,
2333+ " Could not infer the Flutter project to run from given arguments." );
2334+ }
2335+
2336+ // Spawn the engine by using spawner
2337+ auto embedder_engine_spawner =
2338+ reinterpret_cast <flutter::EmbedderEngine*>(engine_spawner);
2339+ auto embedder_engine = embedder_engine_spawner->SpawnEmbedderEngine (
2340+ std::move (settings), //
2341+ std::move (run_configuration), //
2342+ on_create_platform_view, //
2343+ on_create_rasterizer, //
2344+ std::move (external_texture_resolver));
2345+
2346+ if (!embedder_engine->NotifyCreated ()) {
2347+ return LOG_EMBEDDER_ERROR (kInternalInconsistency ,
2348+ " Could not create platform view components." );
2349+ }
2350+
2351+ // Release the ownership of the embedder engine to the caller.
2352+ *engine_out = reinterpret_cast <FLUTTER_API_SYMBOL (FlutterEngine)>(
2353+ embedder_engine.release ());
2354+ return kSuccess ;
2355+ }
2356+
19822357FlutterEngineResult FlutterEngineRunInitialized (
19832358 FLUTTER_API_SYMBOL (FlutterEngine) engine) {
19842359 if (!engine) {
@@ -3074,6 +3449,7 @@ FlutterEngineResult FlutterEngineGetProcAddresses(
30743449 SET_PROC (CreateAOTData, FlutterEngineCreateAOTData);
30753450 SET_PROC (CollectAOTData, FlutterEngineCollectAOTData);
30763451 SET_PROC (Run, FlutterEngineRun);
3452+ SET_PROC (Spawn, FlutterEngineSpawn);
30773453 SET_PROC (Shutdown, FlutterEngineShutdown);
30783454 SET_PROC (Initialize, FlutterEngineInitialize);
30793455 SET_PROC (Deinitialize, FlutterEngineDeinitialize);
0 commit comments