Flutter Engine
FlutterEngine.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
6 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
7 
8 #include <algorithm>
9 #include <vector>
10 
11 #import "flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacDelegate.h"
12 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
13 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h"
14 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h"
15 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.h"
16 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h"
17 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h"
18 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderingBackend.h"
19 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
20 #include "flutter/shell/platform/embedder/embedder.h"
21 
22 /**
23  * Constructs and returns a FlutterLocale struct corresponding to |locale|, which must outlive
24  * the returned struct.
25  */
26 static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) {
27  FlutterLocale flutterLocale = {};
28  flutterLocale.struct_size = sizeof(FlutterLocale);
29  flutterLocale.language_code = [[locale objectForKey:NSLocaleLanguageCode] UTF8String];
30  flutterLocale.country_code = [[locale objectForKey:NSLocaleCountryCode] UTF8String];
31  flutterLocale.script_code = [[locale objectForKey:NSLocaleScriptCode] UTF8String];
32  flutterLocale.variant_code = [[locale objectForKey:NSLocaleVariantCode] UTF8String];
33  return flutterLocale;
34 }
35 
36 /**
37  * Private interface declaration for FlutterEngine.
38  */
39 @interface FlutterEngine () <FlutterBinaryMessenger>
40 
41 /**
42  * Sends the list of user-preferred locales to the Flutter engine.
43  */
44 - (void)sendUserLocales;
45 
46 /**
47  * Handles a platform message from the engine.
48  */
49 - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message;
50 
51 /**
52  * Requests that the task be posted back the to the Flutter engine at the target time. The target
53  * time is in the clock used by the Flutter engine.
54  */
55 - (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime;
56 
57 /**
58  * Loads the AOT snapshots and instructions from the elf bundle (app_elf_snapshot.so) into _aotData,
59  * if it is present in the assets directory.
60  */
61 - (void)loadAOTData:(NSString*)assetsDir;
62 
63 @end
64 
65 #pragma mark -
66 
67 /**
68  * `FlutterPluginRegistrar` implementation handling a single plugin.
69  */
70 @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
71 - (instancetype)initWithPlugin:(nonnull NSString*)pluginKey
72  flutterEngine:(nonnull FlutterEngine*)flutterEngine;
73 @end
74 
75 @implementation FlutterEngineRegistrar {
76  NSString* _pluginKey;
78 }
79 
80 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
81  self = [super init];
82  if (self) {
83  _pluginKey = [pluginKey copy];
85  }
86  return self;
87 }
88 
89 #pragma mark - FlutterPluginRegistrar
90 
91 - (id<FlutterBinaryMessenger>)messenger {
93 }
94 
95 - (id<FlutterTextureRegistry>)textures {
96  return _flutterEngine.renderer;
97 }
98 
99 - (NSView*)view {
100  if (!_flutterEngine.viewController.viewLoaded) {
101  [_flutterEngine.viewController loadView];
102  }
103  return _flutterEngine.viewController.flutterView;
104 }
105 
106 - (void)addMethodCallDelegate:(nonnull id<FlutterPlugin>)delegate
107  channel:(nonnull FlutterMethodChannel*)channel {
108  [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
109  [delegate handleMethodCall:call result:result];
110  }];
111 }
112 
113 @end
114 
115 // Callbacks provided to the engine. See the called methods for documentation.
116 #pragma mark - Static methods provided to engine configuration
117 
119  [engine engineCallbackOnPlatformMessage:message];
120 }
121 
122 #pragma mark -
123 
124 @implementation FlutterEngine {
125  // The embedding-API-level engine object.
127 
128  // The private member for accessibility.
129  std::shared_ptr<flutter::AccessibilityBridge> _bridge;
130 
131  // The project being run by this engine.
133 
134  // A mapping of channel names to the registered handlers for those channels.
135  NSMutableDictionary<NSString*, FlutterBinaryMessageHandler>* _messageHandlers;
136 
137  // Whether the engine can continue running after the view controller is removed.
139 
140  // Pointer to the Dart AOT snapshot and instruction data.
142 
143  // _macOSCompositor is created when the engine is created and
144  // its destruction is handled by ARC when the engine is destroyed.
145  // This is either a FlutterGLCompositor or a FlutterMetalCompositor instance.
146  std::unique_ptr<flutter::FlutterCompositor> _macOSCompositor;
147 
148  // FlutterCompositor is copied and used in embedder.cc.
150 }
151 
152 - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
153  return [self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
154 }
155 
156 - (instancetype)initWithName:(NSString*)labelPrefix
157  project:(FlutterDartProject*)project
158  allowHeadlessExecution:(BOOL)allowHeadlessExecution {
159  self = [super init];
160  NSAssert(self, @"Super init cannot be nil");
161 
162  _project = project ?: [[FlutterDartProject alloc] init];
163  _messageHandlers = [[NSMutableDictionary alloc] init];
164  _allowHeadlessExecution = allowHeadlessExecution;
165  _semanticsEnabled = NO;
166 
167  _embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
168  FlutterEngineGetProcAddresses(&_embedderAPI);
169 
170  if ([FlutterRenderingBackend renderUsingMetal]) {
171  _renderer = [[FlutterMetalRenderer alloc] initWithFlutterEngine:self];
172  } else {
173  _renderer = [[FlutterOpenGLRenderer alloc] initWithFlutterEngine:self];
174  }
175 
176  NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
177  [notificationCenter addObserver:self
178  selector:@selector(sendUserLocales)
179  name:NSCurrentLocaleDidChangeNotification
180  object:nil];
181 
182  return self;
183 }
184 
185 - (void)dealloc {
186  [self shutDownEngine];
187  if (_aotData) {
188  _embedderAPI.CollectAOTData(_aotData);
189  }
190 }
191 
192 - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
193  if (self.running) {
194  return NO;
195  }
196 
198  NSLog(@"Attempted to run an engine with no view controller without headless mode enabled.");
199  return NO;
200  }
201 
202  // TODO(stuartmorgan): Move internal channel registration from FlutterViewController to here.
203 
204  // FlutterProjectArgs is expecting a full argv, so when processing it for
205  // flags the first item is treated as the executable and ignored. Add a dummy
206  // value so that all provided arguments are used.
207  std::vector<std::string> switches = _project.switches;
208  std::vector<const char*> argv = {"placeholder"};
209  std::transform(switches.begin(), switches.end(), std::back_inserter(argv),
210  [](const std::string& arg) -> const char* { return arg.c_str(); });
211 
212  std::vector<const char*> dartEntrypointArgs;
213  for (NSString* argument in [_project dartEntrypointArguments]) {
214  dartEntrypointArgs.push_back([argument UTF8String]);
215  }
216 
217  FlutterProjectArgs flutterArguments = {};
218  flutterArguments.struct_size = sizeof(FlutterProjectArgs);
219  flutterArguments.assets_path = _project.assetsPath.UTF8String;
220  flutterArguments.icu_data_path = _project.ICUDataPath.UTF8String;
221  flutterArguments.command_line_argc = static_cast<int>(argv.size());
222  flutterArguments.command_line_argv = argv.size() > 0 ? argv.data() : nullptr;
224  flutterArguments.update_semantics_node_callback = [](const FlutterSemanticsNode* node,
225  void* user_data) {
227  [engine updateSemanticsNode:node];
228  };
229  flutterArguments.update_semantics_custom_action_callback =
230  [](const FlutterSemanticsCustomAction* action, void* user_data) {
232  [engine updateSemanticsCustomActions:action];
233  };
234  flutterArguments.custom_dart_entrypoint = entrypoint.UTF8String;
235  flutterArguments.shutdown_dart_vm_when_done = true;
236  flutterArguments.dart_entrypoint_argc = dartEntrypointArgs.size();
237  flutterArguments.dart_entrypoint_argv = dartEntrypointArgs.data();
239 
240  static size_t sTaskRunnerIdentifiers = 0;
241  const FlutterTaskRunnerDescription cocoa_task_runner_description = {
243  .user_data = (void*)CFBridgingRetain(self),
244  .runs_task_on_current_thread_callback = [](void* user_data) -> bool {
245  return [[NSThread currentThread] isMainThread];
246  },
247  .post_task_callback = [](FlutterTask task, uint64_t target_time_nanos,
248  void* user_data) -> void {
249  [((__bridge FlutterEngine*)(user_data)) postMainThreadTask:task
250  targetTimeInNanoseconds:target_time_nanos];
251  },
252  .identifier = ++sTaskRunnerIdentifiers,
253  };
254  const FlutterCustomTaskRunners custom_task_runners = {
256  .platform_task_runner = &cocoa_task_runner_description,
257  };
258  flutterArguments.custom_task_runners = &custom_task_runners;
259 
260  [self loadAOTData:_project.assetsPath];
261  if (_aotData) {
262  flutterArguments.aot_data = _aotData;
263  }
264 
265  flutterArguments.compositor = [self createFlutterCompositor];
266 
267  FlutterRendererConfig rendererConfig = [_renderer createRendererConfig];
268  FlutterEngineResult result = _embedderAPI.Initialize(
269  FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine);
270  if (result != kSuccess) {
271  NSLog(@"Failed to initialize Flutter engine: error %d", result);
272  return NO;
273  }
274 
275  result = _embedderAPI.RunInitialized(_engine);
276  if (result != kSuccess) {
277  NSLog(@"Failed to run an initialized engine: error %d", result);
278  return NO;
279  }
280 
281  [self sendUserLocales];
282  [self updateWindowMetrics];
283  [self updateDisplayConfig];
284  return YES;
285 }
286 
287 - (void)loadAOTData:(NSString*)assetsDir {
288  if (!_embedderAPI.RunsAOTCompiledDartCode()) {
289  return;
290  }
291 
292  BOOL isDirOut = false; // required for NSFileManager fileExistsAtPath.
293  NSFileManager* fileManager = [NSFileManager defaultManager];
294 
295  // This is the location where the test fixture places the snapshot file.
296  // For applications built by Flutter tool, this is in "App.framework".
297  NSString* elfPath = [NSString pathWithComponents:@[ assetsDir, @"app_elf_snapshot.so" ]];
298 
299  if (![fileManager fileExistsAtPath:elfPath isDirectory:&isDirOut]) {
300  return;
301  }
302 
303  FlutterEngineAOTDataSource source = {};
305  source.elf_path = [elfPath cStringUsingEncoding:NSUTF8StringEncoding];
306 
307  auto result = _embedderAPI.CreateAOTData(&source, &_aotData);
308  if (result != kSuccess) {
309  NSLog(@"Failed to load AOT data from: %@", elfPath);
310  }
311 }
312 
313 - (void)setViewController:(FlutterViewController*)controller {
314  if (_viewController != controller) {
315  _viewController = controller;
316  [_renderer setFlutterView:controller.flutterView];
317 
318  if (_semanticsEnabled && _bridge) {
319  _bridge->UpdateDelegate(
320  std::make_unique<flutter::AccessibilityBridgeMacDelegate>(self, _viewController));
321  }
322 
323  if (!controller && !_allowHeadlessExecution) {
324  [self shutDownEngine];
325  }
326  }
327 }
328 
329 - (FlutterCompositor*)createFlutterCompositor {
330  // TODO(richardjcai): Add support for creating a FlutterCompositor
331  // with a nil _viewController for headless engines.
332  // https://github.com/flutter/flutter/issues/71606
333  if (!_viewController) {
334  return nil;
335  }
336 
337  __weak FlutterEngine* weakSelf = self;
338 
339  if ([FlutterRenderingBackend renderUsingMetal]) {
340  FlutterMetalRenderer* metalRenderer = reinterpret_cast<FlutterMetalRenderer*>(_renderer);
342  std::make_unique<flutter::FlutterMetalCompositor>(_viewController, metalRenderer.device);
343  _macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
344  if (has_flutter_content) {
345  FlutterMetalRenderer* metalRenderer =
346  reinterpret_cast<FlutterMetalRenderer*>(weakSelf.renderer);
347  return [metalRenderer present:0 /*=textureID*/] == YES;
348  } else {
349  return true;
350  }
351  });
352  } else {
353  FlutterOpenGLRenderer* openGLRenderer = reinterpret_cast<FlutterOpenGLRenderer*>(_renderer);
354  [openGLRenderer.openGLContext makeCurrentContext];
355  _macOSCompositor = std::make_unique<flutter::FlutterGLCompositor>(_viewController,
356  openGLRenderer.openGLContext);
357 
358  _macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
359  if (has_flutter_content) {
360  FlutterOpenGLRenderer* openGLRenderer =
361  reinterpret_cast<FlutterOpenGLRenderer*>(weakSelf.renderer);
362  return [openGLRenderer glPresent] == YES;
363  } else {
364  return true;
365  }
366  });
367  }
368 
369  _compositor = {};
372 
374  FlutterBackingStore* backing_store_out, //
375  void* user_data //
376  ) {
377  return reinterpret_cast<flutter::FlutterCompositor*>(user_data)->CreateBackingStore(
378  config, backing_store_out);
379  };
380 
382  void* user_data //
383  ) {
384  return reinterpret_cast<flutter::FlutterCompositor*>(user_data)->CollectBackingStore(
385  backing_store);
386  };
387 
388  _compositor.present_layers_callback = [](const FlutterLayer** layers, //
389  size_t layers_count, //
390  void* user_data //
391  ) {
392  return reinterpret_cast<flutter::FlutterCompositor*>(user_data)->Present(layers, layers_count);
393  };
394 
396 
397  return &_compositor;
398 }
399 
400 - (id<FlutterBinaryMessenger>)binaryMessenger {
401  // TODO(stuartmorgan): Switch to FlutterBinaryMessengerRelay to avoid plugins
402  // keeping the engine alive.
403  return self;
404 }
405 
406 #pragma mark - Framework-internal methods
407 
408 - (BOOL)running {
409  return _engine != nullptr;
410 }
411 
412 - (void)updateDisplayConfig {
413  if (!_engine) {
414  return;
415  }
416 
417  CVDisplayLinkRef displayLinkRef;
418  CGDirectDisplayID mainDisplayID = CGMainDisplayID();
419  CVDisplayLinkCreateWithCGDisplay(mainDisplayID, &displayLinkRef);
420  CVTime nominal = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLinkRef);
421  if (!(nominal.flags & kCVTimeIsIndefinite)) {
422  double refreshRate = static_cast<double>(nominal.timeScale) / nominal.timeValue;
423 
424  FlutterEngineDisplay display;
425  display.struct_size = sizeof(display);
426  display.display_id = mainDisplayID;
427  display.refresh_rate = round(refreshRate);
428 
429  std::vector<FlutterEngineDisplay> displays = {display};
430  _embedderAPI.NotifyDisplayUpdate(_engine, kFlutterEngineDisplaysUpdateTypeStartup,
431  displays.data(), displays.size());
432  }
433 
434  CVDisplayLinkRelease(displayLinkRef);
435 }
436 
437 - (FlutterEngineProcTable&)embedderAPI {
438  return _embedderAPI;
439 }
440 
441 - (std::weak_ptr<flutter::AccessibilityBridge>)accessibilityBridge {
442  return _bridge;
443 }
444 
445 - (void)updateWindowMetrics {
446  if (!_engine || !_viewController.viewLoaded) {
447  return;
448  }
449  NSView* view = _viewController.flutterView;
450  CGRect scaledBounds = [view convertRectToBacking:view.bounds];
451  CGSize scaledSize = scaledBounds.size;
452  double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;
453 
454  const FlutterWindowMetricsEvent windowMetricsEvent = {
455  .struct_size = sizeof(windowMetricsEvent),
456  .width = static_cast<size_t>(scaledSize.width),
457  .height = static_cast<size_t>(scaledSize.height),
458  .pixel_ratio = pixelRatio,
459  .left = static_cast<size_t>(scaledBounds.origin.x),
460  .top = static_cast<size_t>(scaledBounds.origin.y),
461  };
462  _embedderAPI.SendWindowMetricsEvent(_engine, &windowMetricsEvent);
463 }
464 
465 - (void)sendPointerEvent:(const FlutterPointerEvent&)event {
466  _embedderAPI.SendPointerEvent(_engine, &event, 1);
467 }
468 
469 - (void)sendKeyEvent:(const FlutterKeyEvent&)event
471  userData:(void*)userData {
472  _embedderAPI.SendKeyEvent(_engine, &event, callback, userData);
473 }
474 
475 - (void)setSemanticsEnabled:(BOOL)enabled {
476  if (_semanticsEnabled == enabled) {
477  return;
478  }
479  _semanticsEnabled = enabled;
480  // Remove the accessibility children from flutter view before reseting the bridge.
481  if (!_semanticsEnabled && self.viewController.viewLoaded) {
482  self.viewController.flutterView.accessibilityChildren = nil;
483  }
484  if (!_semanticsEnabled && _bridge) {
485  _bridge.reset();
486  } else if (_semanticsEnabled && !_bridge) {
487  _bridge = std::make_shared<flutter::AccessibilityBridge>(
488  std::make_unique<flutter::AccessibilityBridgeMacDelegate>(self, self.viewController));
489  }
490  _embedderAPI.UpdateSemanticsEnabled(_engine, _semanticsEnabled);
491 }
492 
493 - (void)dispatchSemanticsAction:(FlutterSemanticsAction)action
494  toTarget:(uint16_t)target
495  withData:(fml::MallocMapping)data {
496  _embedderAPI.DispatchSemanticsAction(_engine, target, action, data.GetMapping(), data.GetSize());
497 }
498 
499 #pragma mark - Private methods
500 
501 - (void)sendUserLocales {
502  if (!self.running) {
503  return;
504  }
505 
506  // Create a list of FlutterLocales corresponding to the preferred languages.
507  NSMutableArray<NSLocale*>* locales = [NSMutableArray array];
508  std::vector<FlutterLocale> flutterLocales;
509  flutterLocales.reserve(locales.count);
510  for (NSString* localeID in [NSLocale preferredLanguages]) {
511  NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
512  [locales addObject:locale];
513  flutterLocales.push_back(FlutterLocaleFromNSLocale(locale));
514  }
515  // Convert to a list of pointers, and send to the engine.
516  std::vector<const FlutterLocale*> flutterLocaleList;
517  flutterLocaleList.reserve(flutterLocales.size());
519  flutterLocales.begin(), flutterLocales.end(), std::back_inserter(flutterLocaleList),
520  [](const auto& arg) -> const auto* { return &arg; });
521  _embedderAPI.UpdateLocales(_engine, flutterLocaleList.data(), flutterLocaleList.size());
522 }
523 
524 - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message {
525  NSData* messageData = nil;
526  if (message->message_size > 0) {
527  messageData = [NSData dataWithBytesNoCopy:(void*)message->message
528  length:message->message_size
529  freeWhenDone:NO];
530  }
531  NSString* channel = @(message->channel);
532  __block const FlutterPlatformMessageResponseHandle* responseHandle = message->response_handle;
533 
534  FlutterBinaryReply binaryResponseHandler = ^(NSData* response) {
535  if (responseHandle) {
536  _embedderAPI.SendPlatformMessageResponse(self->_engine, responseHandle,
537  static_cast<const uint8_t*>(response.bytes),
538  response.length);
539  responseHandle = NULL;
540  } else {
541  NSLog(@"Error: Message responses can be sent only once. Ignoring duplicate response "
542  "on channel '%@'.",
543  channel);
544  }
545  };
546 
547  FlutterBinaryMessageHandler channelHandler = _messageHandlers[channel];
548  if (channelHandler) {
549  channelHandler(messageData, binaryResponseHandler);
550  } else {
551  binaryResponseHandler(nil);
552  }
553 }
554 
555 /**
556  * Note: Called from dealloc. Should not use accessors or other methods.
557  */
558 - (void)shutDownEngine {
559  if (_engine == nullptr) {
560  return;
561  }
562 
563  if (_viewController && _viewController.flutterView) {
564  [_viewController.flutterView shutdown];
565  }
566 
567  FlutterEngineResult result = _embedderAPI.Deinitialize(_engine);
568  if (result != kSuccess) {
569  NSLog(@"Could not de-initialize the Flutter engine: error %d", result);
570  }
571 
572  // Balancing release for the retain in the task runner dispatch table.
573  CFRelease((CFTypeRef)self);
574 
575  result = _embedderAPI.Shutdown(_engine);
576  if (result != kSuccess) {
577  NSLog(@"Failed to shut down Flutter engine: error %d", result);
578  }
579  _engine = nullptr;
580 }
581 
582 #pragma mark - FlutterBinaryMessenger
583 
584 - (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message {
585  [self sendOnChannel:channel message:message binaryReply:nil];
586 }
587 
588 - (void)sendOnChannel:(NSString*)channel
589  message:(NSData* _Nullable)message
590  binaryReply:(FlutterBinaryReply _Nullable)callback {
591  FlutterPlatformMessageResponseHandle* response_handle = nullptr;
592  if (callback) {
593  struct Captures {
594  FlutterBinaryReply reply;
595  };
596  auto captures = std::make_unique<Captures>();
597  captures->reply = callback;
598  auto message_reply = [](const uint8_t* data, size_t data_size, void* user_data) {
599  auto captures = reinterpret_cast<Captures*>(user_data);
600  NSData* reply_data = nil;
601  if (data != nullptr && data_size > 0) {
602  reply_data = [NSData dataWithBytes:static_cast<const void*>(data) length:data_size];
603  }
604  captures->reply(reply_data);
605  delete captures;
606  };
607 
608  FlutterEngineResult create_result = _embedderAPI.PlatformMessageCreateResponseHandle(
609  _engine, message_reply, captures.get(), &response_handle);
610  if (create_result != kSuccess) {
611  NSLog(@"Failed to create a FlutterPlatformMessageResponseHandle (%d)", create_result);
612  return;
613  }
614  captures.release();
615  }
616 
617  FlutterPlatformMessage platformMessage = {
619  .channel = [channel UTF8String],
620  .message = static_cast<const uint8_t*>(message.bytes),
621  .message_size = message.length,
622  .response_handle = response_handle,
623  };
624 
625  FlutterEngineResult message_result = _embedderAPI.SendPlatformMessage(_engine, &platformMessage);
626  if (message_result != kSuccess) {
627  NSLog(@"Failed to send message to Flutter engine on channel '%@' (%d).", channel,
628  message_result);
629  }
630 
631  if (response_handle != nullptr) {
632  FlutterEngineResult release_result =
633  _embedderAPI.PlatformMessageReleaseResponseHandle(_engine, response_handle);
634  if (release_result != kSuccess) {
635  NSLog(@"Failed to release the response handle (%d).", release_result);
636  };
637  }
638 }
639 
640 - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString*)channel
641  binaryMessageHandler:
642  (nullable FlutterBinaryMessageHandler)handler {
643  _messageHandlers[channel] = [handler copy];
644  return 0;
645 }
646 
647 - (void)cleanupConnection:(FlutterBinaryMessengerConnection)connection {
648  // There hasn't been a need to implement this yet for macOS.
649 }
650 
651 #pragma mark - FlutterPluginRegistry
652 
653 - (id<FlutterPluginRegistrar>)registrarForPlugin:(NSString*)pluginName {
654  return [[FlutterEngineRegistrar alloc] initWithPlugin:pluginName flutterEngine:self];
655 }
656 
657 #pragma mark - FlutterTextureRegistrar
658 
659 - (int64_t)registerTexture:(id<FlutterTexture>)texture {
660  return [_renderer registerTexture:texture];
661 }
662 
663 - (BOOL)registerTextureWithID:(int64_t)textureId {
664  return _embedderAPI.RegisterExternalTexture(_engine, textureId) == kSuccess;
665 }
666 
667 - (void)textureFrameAvailable:(int64_t)textureID {
668  [_renderer textureFrameAvailable:textureID];
669 }
670 
671 - (BOOL)markTextureFrameAvailable:(int64_t)textureID {
672  return _embedderAPI.MarkExternalTextureFrameAvailable(_engine, textureID) == kSuccess;
673 }
674 
675 - (void)unregisterTexture:(int64_t)textureID {
676  [_renderer unregisterTexture:textureID];
677 }
678 
679 - (BOOL)unregisterTextureWithID:(int64_t)textureID {
680  return _embedderAPI.UnregisterExternalTexture(_engine, textureID) == kSuccess;
681 }
682 
683 - (void)updateSemanticsNode:(const FlutterSemanticsNode*)node {
684  NSAssert(_bridge, @"The accessibility bridge must be initialized.");
686  return;
687  }
688  _bridge->AddFlutterSemanticsNodeUpdate(node);
689 }
690 
691 - (void)updateSemanticsCustomActions:(const FlutterSemanticsCustomAction*)action {
692  NSAssert(_bridge, @"The accessibility bridge must be initialized.");
694  // Custom action with id = kFlutterSemanticsNodeIdBatchEnd indicates this is
695  // the end of the update batch.
696  _bridge->CommitUpdates();
697  // Accessibility tree can only be used when the view is loaded.
698  if (!self.viewController.viewLoaded) {
699  return;
700  }
701  // Attaches the accessibility root to the flutter view.
702  auto root = _bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
703  if (root) {
704  if ([self.viewController.flutterView.accessibilityChildren count] == 0) {
705  NSAccessibilityElement* native_root = root->GetNativeViewAccessible();
706  self.viewController.flutterView.accessibilityChildren = @[ native_root ];
707  }
708  } else {
709  self.viewController.flutterView.accessibilityChildren = nil;
710  }
711  return;
712  }
713  _bridge->AddFlutterSemanticsCustomActionUpdate(action);
714 }
715 
716 #pragma mark - Task runner integration
717 
718 - (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
719  const auto engine_time = _embedderAPI.GetCurrentTime();
720 
721  __weak FlutterEngine* weak_self = self;
722  auto worker = ^{
723  FlutterEngine* strong_self = weak_self;
724  if (strong_self && strong_self->_engine) {
725  auto result = _embedderAPI.RunTask(strong_self->_engine, &task);
726  if (result != kSuccess) {
727  NSLog(@"Could not post a task to the Flutter engine.");
728  }
729  }
730  };
731 
732  if (targetTime <= engine_time) {
733  dispatch_async(dispatch_get_main_queue(), worker);
734 
735  } else {
736  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, targetTime - engine_time),
737  dispatch_get_main_queue(), worker);
738  }
739 }
740 
741 // Getter used by test harness, only exposed through the FlutterEngine(Test) category
742 - (flutter::FlutterCompositor*)macOSCompositor {
743  return _macOSCompositor.get();
744 }
745 
746 @end
size_t struct_size
This size of this struct. Must be sizeof(FlutterLocale).
Definition: embedder.h:1152
const FlutterCompositor * compositor
Definition: embedder.h:1528
static void OnPlatformMessage(const FlutterPlatformMessage *message, FlutterEngine *engine)
struct _FlutterEngine * FLUTTER_API_SYMBOL(FlutterEngine)
Definition: embedder.h:228
BOOL _allowHeadlessExecution
G_BEGIN_DECLS FlTexture * texture
NSObject< FlutterBinaryMessenger > * binaryMessenger
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
void(* rootIsolateCreateCallback)(void *_Nullable)
const char * icu_data_path
Definition: embedder.h:1378
bool avoid_backing_store_cache
Avoid caching backing stores provided by this compositor.
Definition: embedder.h:1147
size_t struct_size
The size of this struct. Must be sizeof(FlutterTaskRunnerDescription).
Definition: embedder.h:913
const FlutterCustomTaskRunners * custom_task_runners
Definition: embedder.h:1493
Function-pointer-based versions of the APIs above.
Definition: embedder.h:2372
static FlutterLocale FlutterLocaleFromNSLocale(NSLocale *locale)
_FlutterEngineAOTData * _aotData
void * user_data
const char * variant_code
Definition: embedder.h:1171
GAsyncResult * result
NSOpenGLContext * openGLContext
BOOL present:(int64_t textureID)
size_t struct_size
This size of this struct. Must be sizeof(FlutterDisplay).
Definition: embedder.h:1193
FlutterPlatformMessageCallback platform_message_callback
Definition: embedder.h:1402
FlKeyEvent FlKeyResponderAsyncCallback callback
const char *const * command_line_argv
Definition: embedder.h:1396
FlutterSemanticsAction
Definition: embedder.h:101
FlKeyEvent * event
const char * script_code
Definition: embedder.h:1166
const char * country_code
Definition: embedder.h:1161
bool shutdown_dart_vm_when_done
Definition: embedder.h:1512
const char *const * dart_entrypoint_argv
Definition: embedder.h:1566
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
fml::scoped_nsobject< FlutterEngine > _engine
void(* FlutterPlatformMessageCallback)(const FlutterPlatformMessage *, void *)
Definition: embedder.h:770
#define FLUTTER_ENGINE_VERSION
Definition: embedder.h:63
FlutterDartProject * _project
const FlutterSemanticsNode * node
Definition: fl_view.cc:83
uint32_t * target
FlutterUpdateSemanticsNodeCallback update_semantics_node_callback
Definition: embedder.h:1446
std::shared_ptr< flutter::AccessibilityBridge > _bridge
NSMutableDictionary< NSString *, FlutterBinaryMessageHandler > * _messageHandlers
SemanticsAction action
int32_t id
The unique identifier for this node.
Definition: embedder.h:798
FlutterUpdateSemanticsCustomActionCallback update_semantics_custom_action_callback
Definition: embedder.h:1457
std::unique_ptr< flutter::FlutterCompositor > _macOSCompositor
int32_t width
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:565
FlutterEngineResult FlutterEngineGetProcAddresses(FlutterEngineProcTable *table)
Gets the table of engine function pointers.
Definition: embedder.cc:2291
const char * custom_dart_entrypoint
Definition: embedder.h:1488
FlutterBackingStoreCollectCallback collect_backing_store_callback
Definition: embedder.h:1142
const char * assets_path
Definition: embedder.h:1354
const int32_t kFlutterSemanticsNodeIdBatchEnd
Definition: embedder.cc:69
int BOOL
Definition: windows_types.h:37
FlutterEngineResult
Definition: embedder.h:65
size_t struct_size
The size of this struct. Must be sizeof(FlutterProjectArgs).
Definition: embedder.h:1350
fml::WeakPtr< FlutterViewController > _viewController
std::vector< std::string > switches
FlutterLayersPresentCallback present_layers_callback
Definition: embedder.h:1145
FlView * view
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition: mapping.h:129
size_t struct_size
This size of this struct. Must be sizeof(FlutterCompositor).
Definition: embedder.h:1126
FlutterEngineAOTDataSourceType type
Definition: embedder.h:1326
void(* FlutterKeyEventCallback)(bool, void *)
Definition: embedder.h:748
FlutterEngineAOTData aot_data
Definition: embedder.h:1543
size_t struct_size
The size of this struct. Must be sizeof(FlutterCustomTaskRunners).
Definition: embedder.h:938
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformMessage).
Definition: embedder.h:757
int64_t FlutterBinaryMessengerConnection
const char * language_code
Definition: embedder.h:1156
VoidCallback root_isolate_create_callback
Definition: embedder.h:1437
int command_line_argc
The command line argument count used to initialize the project.
Definition: embedder.h:1380
const char * elf_path
Absolute path to an ELF library file.
Definition: embedder.h:1329
FlutterCompositor _compositor
FlutterViewController * viewController
FlutterEngine * flutterEngine
FlutterEngine * _flutterEngine
FlutterBackingStoreCreateCallback create_backing_store_callback
Definition: embedder.h:1139