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 #define FML_USED_ON_EMBEDDER
6 
7 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h"
8 
9 #include <memory>
10 
11 #include "flutter/fml/message_loop.h"
12 #include "flutter/fml/platform/darwin/platform_version.h"
13 #include "flutter/fml/trace_event.h"
14 #include "flutter/runtime/ptrace_check.h"
15 #include "flutter/shell/common/engine.h"
16 #include "flutter/shell/common/platform_view.h"
17 #include "flutter/shell/common/shell.h"
18 #include "flutter/shell/common/switches.h"
19 #include "flutter/shell/common/thread_host.h"
20 #import "flutter/shell/platform/darwin/common/command_line.h"
21 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterBinaryMessengerRelay.h"
22 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
23 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.h"
24 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h"
25 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h"
26 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
27 #import "flutter/shell/platform/darwin/ios/framework/Source/connection_collection.h"
28 #import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
29 #import "flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h"
30 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
31 #import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
32 #import "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
33 #include "flutter/shell/profiling/sampling_profiler.h"
34 
35 NSString* const FlutterDefaultDartEntrypoint = nil;
36 NSString* const FlutterDefaultInitialRoute = nil;
37 NSString* const FlutterEngineWillDealloc = @"FlutterEngineWillDealloc";
38 static constexpr int kNumProfilerSamplesPerSec = 5;
39 
40 @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
41 @property(nonatomic, assign) FlutterEngine* flutterEngine;
42 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
43 @end
44 
45 @interface FlutterEngine () <FlutterTextInputDelegate, FlutterBinaryMessenger>
46 // Maintains a dictionary of plugin names that have registered with the engine. Used by
47 // FlutterEngineRegistrar to implement a FlutterPluginRegistrar.
48 @property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
49 @property(nonatomic, readonly) NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* registrars;
50 
51 @property(nonatomic, readwrite, copy) NSString* isolateId;
52 @property(nonatomic, copy) NSString* initialRoute;
53 @property(nonatomic, retain) id<NSObject> flutterViewControllerWillDeallocObserver;
54 @end
55 
56 @implementation FlutterEngine {
58  std::shared_ptr<flutter::ThreadHost> _threadHost;
59  std::unique_ptr<flutter::Shell> _shell;
60  NSString* _labelPrefix;
61  std::unique_ptr<fml::WeakPtrFactory<FlutterEngine>> _weakFactory;
62 
65 
66  std::shared_ptr<flutter::FlutterPlatformViewsController> _platformViewsController;
68  std::shared_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
69  std::shared_ptr<flutter::SamplingProfiler> _profiler;
70 
71  // Channels
85 
86  int64_t _nextTextureId;
87 
91  std::unique_ptr<flutter::ConnectionCollection> _connections;
92 }
93 
94 - (instancetype)init {
95  return [self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
96 }
97 
98 - (instancetype)initWithName:(NSString*)labelPrefix {
99  return [self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
100 }
101 
102 - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
103  return [self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
104 }
105 
106 - (instancetype)initWithName:(NSString*)labelPrefix
107  project:(FlutterDartProject*)project
108  allowHeadlessExecution:(BOOL)allowHeadlessExecution {
109  return [self initWithName:labelPrefix
110  project:project
111  allowHeadlessExecution:allowHeadlessExecution
112  restorationEnabled:NO];
113 }
114 
115 - (instancetype)initWithName:(NSString*)labelPrefix
116  project:(FlutterDartProject*)project
117  allowHeadlessExecution:(BOOL)allowHeadlessExecution
118  restorationEnabled:(BOOL)restorationEnabled {
119  self = [super init];
120  NSAssert(self, @"Super init cannot be nil");
121  NSAssert(labelPrefix, @"labelPrefix is required");
122 
123  _restorationEnabled = restorationEnabled;
124  _allowHeadlessExecution = allowHeadlessExecution;
125  _labelPrefix = [labelPrefix copy];
126 
127  _weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterEngine>>(self);
128 
129  if (project == nil) {
130  _dartProject.reset([[FlutterDartProject alloc] init]);
131  } else {
132  _dartProject.reset([project retain]);
133  }
134 
135  if (!EnableTracingIfNecessary([_dartProject.get() settings])) {
136  NSLog(
137  @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
138  @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
139  @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
140  @"profile and release mode apps can be launched from the home screen.");
141  [self release];
142  return nil;
143  }
144 
145  _pluginPublications = [[NSMutableDictionary alloc] init];
146  _registrars = [[NSMutableDictionary alloc] init];
147  [self recreatePlatformViewController];
148 
149  _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
151 
152  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
153  [center addObserver:self
154  selector:@selector(onMemoryWarning:)
155  name:UIApplicationDidReceiveMemoryWarningNotification
156  object:nil];
157 
158  [center addObserver:self
159  selector:@selector(applicationWillEnterForeground:)
160  name:UIApplicationWillEnterForegroundNotification
161  object:nil];
162 
163  [center addObserver:self
164  selector:@selector(applicationDidEnterBackground:)
165  name:UIApplicationDidEnterBackgroundNotification
166  object:nil];
167 
168  [center addObserver:self
169  selector:@selector(onLocaleUpdated:)
170  name:NSCurrentLocaleDidChangeNotification
171  object:nil];
172 
173  return self;
174 }
175 
176 - (void)recreatePlatformViewController {
179 }
180 
181 - (flutter::IOSRenderingAPI)platformViewsRenderingAPI {
182  return _renderingApi;
183 }
184 
185 - (void)dealloc {
186  /// Notify plugins of dealloc. This should happen first in dealloc since the
187  /// plugins may be talking to things like the binaryMessenger.
188  [_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
189  if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
190  NSObject<FlutterPluginRegistrar>* registrar = self.registrars[key];
191  [object detachFromEngineForRegistrar:registrar];
192  }
193  }];
194 
195  [[NSNotificationCenter defaultCenter] postNotificationName:FlutterEngineWillDealloc
196  object:self
197  userInfo:nil];
198 
199  /// nil out weak references.
200  [_registrars
201  enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) {
202  registrar.flutterEngine = nil;
203  }];
204 
205  [_labelPrefix release];
206  [_initialRoute release];
207  [_pluginPublications release];
208  [_registrars release];
209  _binaryMessenger.parent = nil;
210  [_binaryMessenger release];
211 
212  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
213  if (_flutterViewControllerWillDeallocObserver) {
214  [center removeObserver:_flutterViewControllerWillDeallocObserver];
215  [_flutterViewControllerWillDeallocObserver release];
216  }
217  [center removeObserver:self];
218 
219  [super dealloc];
220 }
221 
222 - (flutter::Shell&)shell {
224  return *_shell;
225 }
226 
227 - (fml::WeakPtr<FlutterEngine>)getWeakPtr {
228  return _weakFactory->GetWeakPtr();
229 }
230 
231 - (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics {
232  if (!self.platformView) {
233  return;
234  }
235  self.platformView->SetViewportMetrics(std::move(viewportMetrics));
236 }
237 
238 - (void)dispatchPointerDataPacket:(std::unique_ptr<flutter::PointerDataPacket>)packet {
239  if (!self.platformView) {
240  return;
241  }
242  self.platformView->DispatchPointerDataPacket(std::move(packet));
243 }
244 
245 - (fml::WeakPtr<flutter::PlatformView>)platformView {
247  return _shell->GetPlatformView();
248 }
249 
250 - (flutter::PlatformViewIOS*)iosPlatformView {
252  return static_cast<flutter::PlatformViewIOS*>(_shell->GetPlatformView().get());
253 }
254 
255 - (fml::RefPtr<fml::TaskRunner>)platformTaskRunner {
257  return _shell->GetTaskRunners().GetPlatformTaskRunner();
258 }
259 
260 - (fml::RefPtr<fml::TaskRunner>)RasterTaskRunner {
262  return _shell->GetTaskRunners().GetRasterTaskRunner();
263 }
264 
265 - (void)sendKeyEvent:(const FlutterKeyEvent&)event
267  userData:(void*)userData API_AVAILABLE(ios(13.4)) {
268  if (@available(iOS 13.4, *)) {
269  } else {
270  return;
271  }
272  if (!self.platformView) {
273  return;
274  }
275  const char* character = event.character;
276 
277  flutter::KeyData key_data;
278  key_data.Clear();
279  key_data.timestamp = (uint64_t)event.timestamp;
280  switch (event.type) {
282  key_data.type = flutter::KeyEventType::kUp;
283  break;
286  break;
289  break;
290  }
291  key_data.physical = event.physical;
292  key_data.logical = event.logical;
293  key_data.synthesized = event.synthesized;
294 
295  auto packet = std::make_unique<flutter::KeyDataPacket>(key_data, character);
296 
297  auto response = [callback, userData](bool handled) {
298  if (callback != nullptr) {
299  callback(handled, userData);
300  }
301  };
302  self.platformView->DispatchKeyDataPacket(std::move(packet), std::move(response));
303 }
304 
305 - (void)ensureSemanticsEnabled {
306  self.iosPlatformView->SetSemanticsEnabled(true);
307 }
308 
309 - (void)setViewController:(FlutterViewController*)viewController {
310  FML_DCHECK(self.iosPlatformView);
312  viewController ? [viewController getWeakPtr] : fml::WeakPtr<FlutterViewController>();
313  self.iosPlatformView->SetOwnerViewController(_viewController);
314  [self maybeSetupPlatformViewChannels];
315 
316  if (viewController) {
317  __block FlutterEngine* blockSelf = self;
318  self.flutterViewControllerWillDeallocObserver =
319  [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
320  object:viewController
321  queue:[NSOperationQueue mainQueue]
322  usingBlock:^(NSNotification* note) {
323  [blockSelf notifyViewControllerDeallocated];
324  }];
325  } else {
326  self.flutterViewControllerWillDeallocObserver = nil;
327  [self notifyLowMemory];
328  }
329 }
330 
331 - (void)attachView {
332  self.iosPlatformView->attachView();
333 }
334 
335 - (void)setFlutterViewControllerWillDeallocObserver:(id<NSObject>)observer {
336  if (observer != _flutterViewControllerWillDeallocObserver) {
337  if (_flutterViewControllerWillDeallocObserver) {
338  [[NSNotificationCenter defaultCenter]
339  removeObserver:_flutterViewControllerWillDeallocObserver];
340  [_flutterViewControllerWillDeallocObserver release];
341  }
342  _flutterViewControllerWillDeallocObserver = [observer retain];
343  }
344 }
345 
346 - (void)notifyViewControllerDeallocated {
347  [[self lifecycleChannel] sendMessage:@"AppLifecycleState.detached"];
349  [self destroyContext];
350  } else {
351  flutter::PlatformViewIOS* platform_view = [self iosPlatformView];
352  if (platform_view) {
353  platform_view->SetOwnerViewController({});
354  }
355  }
356  _viewController.reset();
357 }
358 
359 - (void)destroyContext {
360  [self resetChannels];
361  self.isolateId = nil;
362  _shell.reset();
363  _profiler.reset();
364  _threadHost.reset();
365  _platformViewsController.reset();
366 }
367 
368 - (FlutterViewController*)viewController {
369  if (!_viewController) {
370  return nil;
371  }
372  return _viewController.get();
373 }
374 
375 - (FlutterPlatformPlugin*)platformPlugin {
376  return _platformPlugin.get();
377 }
378 - (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController {
380 }
382  return _textInputPlugin.get();
383 }
384 - (FlutterRestorationPlugin*)restorationPlugin {
385  return _restorationPlugin.get();
386 }
387 - (FlutterMethodChannel*)localizationChannel {
388  return _localizationChannel.get();
389 }
390 - (FlutterMethodChannel*)navigationChannel {
391  return _navigationChannel.get();
392 }
393 - (FlutterMethodChannel*)restorationChannel {
394  return _restorationChannel.get();
395 }
396 - (FlutterMethodChannel*)platformChannel {
397  return _platformChannel.get();
398 }
399 - (FlutterMethodChannel*)textInputChannel {
400  return _textInputChannel.get();
401 }
402 - (FlutterBasicMessageChannel*)lifecycleChannel {
403  return _lifecycleChannel.get();
404 }
405 - (FlutterBasicMessageChannel*)systemChannel {
406  return _systemChannel.get();
407 }
408 - (FlutterBasicMessageChannel*)settingsChannel {
409  return _settingsChannel.get();
410 }
411 - (FlutterBasicMessageChannel*)keyEventChannel {
412  return _keyEventChannel.get();
413 }
414 
415 - (NSURL*)observatoryUrl {
416  return [_publisher.get() url];
417 }
418 
419 - (void)resetChannels {
426  _lifecycleChannel.reset();
427  _systemChannel.reset();
428  _settingsChannel.reset();
429  _keyEventChannel.reset();
430 }
431 
432 - (void)startProfiler {
433  FML_DCHECK(!_threadHost->name_prefix.empty());
434  _profiler_metrics = std::make_shared<flutter::ProfilerMetricsIOS>();
435  _profiler = std::make_shared<flutter::SamplingProfiler>(
436  _threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(),
437  [self]() { return self->_profiler_metrics->GenerateSample(); }, kNumProfilerSamplesPerSec);
438  _profiler->Start();
439 }
440 
441 // If you add a channel, be sure to also update `resetChannels`.
442 // Channels get a reference to the engine, and therefore need manual
443 // cleanup for proper collection.
444 - (void)setupChannels {
445  // This will be invoked once the shell is done setting up and the isolate ID
446  // for the UI isolate is available.
447  fml::WeakPtr<FlutterEngine> weakSelf = [self getWeakPtr];
448  [_binaryMessenger setMessageHandlerOnChannel:@"flutter/isolate"
449  binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
450  if (weakSelf) {
451  weakSelf.get().isolateId =
452  [[FlutterStringCodec sharedInstance] decode:message];
453  }
454  }];
455 
457  initWithName:@"flutter/localization"
458  binaryMessenger:self.binaryMessenger
459  codec:[FlutterJSONMethodCodec sharedInstance]]);
460 
462  initWithName:@"flutter/navigation"
463  binaryMessenger:self.binaryMessenger
464  codec:[FlutterJSONMethodCodec sharedInstance]]);
465 
466  if ([_initialRoute length] > 0) {
467  // Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
468  [_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
469  [_initialRoute release];
470  _initialRoute = nil;
471  }
472 
474  initWithName:@"flutter/restoration"
475  binaryMessenger:self.binaryMessenger
476  codec:[FlutterStandardMethodCodec sharedInstance]]);
477 
479  initWithName:@"flutter/platform"
480  binaryMessenger:self.binaryMessenger
481  codec:[FlutterJSONMethodCodec sharedInstance]]);
482 
484  initWithName:@"flutter/platform_views"
485  binaryMessenger:self.binaryMessenger
486  codec:[FlutterStandardMethodCodec sharedInstance]]);
487 
489  initWithName:@"flutter/textinput"
490  binaryMessenger:self.binaryMessenger
491  codec:[FlutterJSONMethodCodec sharedInstance]]);
492 
494  initWithName:@"flutter/lifecycle"
495  binaryMessenger:self.binaryMessenger
496  codec:[FlutterStringCodec sharedInstance]]);
497 
499  initWithName:@"flutter/system"
500  binaryMessenger:self.binaryMessenger
501  codec:[FlutterJSONMessageCodec sharedInstance]]);
502 
504  initWithName:@"flutter/settings"
505  binaryMessenger:self.binaryMessenger
506  codec:[FlutterJSONMessageCodec sharedInstance]]);
507 
509  initWithName:@"flutter/keyevent"
510  binaryMessenger:self.binaryMessenger
511  codec:[FlutterJSONMessageCodec sharedInstance]]);
512 
513  _textInputPlugin.reset([[FlutterTextInputPlugin alloc] init]);
514  _textInputPlugin.get().textInputDelegate = self;
515 
516  _platformPlugin.reset([[FlutterPlatformPlugin alloc] initWithEngine:[self getWeakPtr]]);
517 
519  initWithChannel:_restorationChannel.get()
520  restorationEnabled:_restorationEnabled]);
521 }
522 
523 - (void)maybeSetupPlatformViewChannels {
524  if (_shell && self.shell.IsSetup()) {
525  FlutterPlatformPlugin* platformPlugin = _platformPlugin.get();
526  [_platformChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
527  [platformPlugin handleMethodCall:call result:result];
528  }];
529 
530  fml::WeakPtr<FlutterEngine> weakSelf = [self getWeakPtr];
531  [_platformViewsChannel.get()
532  setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
533  if (weakSelf) {
534  weakSelf.get().platformViewsController->OnMethodCall(call, result);
535  }
536  }];
537 
539  [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
540  [textInputPlugin handleMethodCall:call result:result];
541  }];
542  }
543 }
544 
546  base64Encode:(bool)base64Encode {
547  return self.shell.Screenshot(type, base64Encode);
548 }
549 
550 - (void)launchEngine:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil {
551  // Launch the Dart application with the inferred run configuration.
552  self.shell.RunEngine([_dartProject.get() runConfigurationForEntrypoint:entrypoint
553  libraryOrNil:libraryOrNil]);
554 }
555 
556 - (void)setupShell:(std::unique_ptr<flutter::Shell>)shell
557  withObservatoryPublication:(BOOL)doesObservatoryPublication {
558  _shell = std::move(shell);
559  [self setupChannels];
560  [self onLocaleUpdated:nil];
561  [self initializeDisplays];
563  initWithEnableObservatoryPublication:doesObservatoryPublication]);
564  [self maybeSetupPlatformViewChannels];
565  _shell->SetGpuAvailability(_isGpuDisabled ? flutter::GpuAvailability::kUnavailable
567 }
568 
569 + (BOOL)isProfilerEnabled {
570  bool profilerEnabled = false;
571 #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
572  (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
573  profilerEnabled = true;
574 #endif
575  return profilerEnabled;
576 }
577 
578 + (NSString*)generateThreadLabel:(NSString*)labelPrefix {
579  static size_t s_shellCount = 0;
580  return [NSString stringWithFormat:@"%@.%zu", labelPrefix, ++s_shellCount];
581 }
582 
583 + (flutter::ThreadHost)makeThreadHost:(NSString*)threadLabel {
584  // The current thread will be used as the platform thread. Ensure that the message loop is
585  // initialized.
587 
588  uint32_t threadHostType = flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::RASTER |
589  flutter::ThreadHost::Type::IO;
590  if ([FlutterEngine isProfilerEnabled]) {
591  threadHostType = threadHostType | flutter::ThreadHost::Type::Profiler;
592  }
593  return {threadLabel.UTF8String, // label
594  threadHostType};
595 }
596 
597 static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
598  if (libraryURI) {
599  FML_DCHECK(entrypoint) << "Must specify entrypoint if specifying library";
600  settings->advisory_script_entrypoint = entrypoint.UTF8String;
601  settings->advisory_script_uri = libraryURI.UTF8String;
602  } else if (entrypoint) {
603  settings->advisory_script_entrypoint = entrypoint.UTF8String;
604  settings->advisory_script_uri = std::string("main.dart");
605  } else {
606  settings->advisory_script_entrypoint = std::string("main");
607  settings->advisory_script_uri = std::string("main.dart");
608  }
609 }
610 
611 - (BOOL)createShell:(NSString*)entrypoint
612  libraryURI:(NSString*)libraryURI
613  initialRoute:(NSString*)initialRoute {
614  if (_shell != nullptr) {
615  FML_LOG(WARNING) << "This FlutterEngine was already invoked.";
616  return NO;
617  }
618 
619  self.initialRoute = initialRoute;
620 
621  auto settings = [_dartProject.get() settings];
623 
624  auto platformData = [_dartProject.get() defaultPlatformData];
625 
626  SetEntryPoint(&settings, entrypoint, libraryURI);
627 
628  NSString* threadLabel = [FlutterEngine generateThreadLabel:_labelPrefix];
629  _threadHost = std::make_shared<flutter::ThreadHost>();
630  *_threadHost = [FlutterEngine makeThreadHost:threadLabel];
631 
632  // Lambda captures by pointers to ObjC objects are fine here because the
633  // create call is synchronous.
635  [self](flutter::Shell& shell) {
636  [self recreatePlatformViewController];
637  return std::make_unique<flutter::PlatformViewIOS>(
638  shell, self->_renderingApi, self->_platformViewsController, shell.GetTaskRunners());
639  };
640 
642  [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
643 
644  flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
646  _threadHost->raster_thread->GetTaskRunner(), // raster
647  _threadHost->ui_thread->GetTaskRunner(), // ui
648  _threadHost->io_thread->GetTaskRunner() // io
649  );
650 
651  _isGpuDisabled =
652  [UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
653  // Create the shell. This is a blocking operation.
654  std::unique_ptr<flutter::Shell> shell = flutter::Shell::Create(
655  /*platform_data=*/std::move(platformData),
656  /*task_runners=*/std::move(task_runners),
657  /*settings=*/std::move(settings),
658  /*on_create_platform_view=*/on_create_platform_view,
659  /*on_create_rasterizer=*/on_create_rasterizer,
660  /*is_gpu_disabled=*/_isGpuDisabled);
661 
662  if (shell == nullptr) {
663  FML_LOG(ERROR) << "Could not start a shell FlutterEngine with entrypoint: "
664  << entrypoint.UTF8String;
665  } else {
666  [self setupShell:std::move(shell)
667  withObservatoryPublication:settings.enable_observatory_publication];
668  if ([FlutterEngine isProfilerEnabled]) {
669  [self startProfiler];
670  }
671  }
672 
673  return _shell != nullptr;
674 }
675 
676 - (void)initializeDisplays {
677  double refresh_rate = [DisplayLinkManager displayRefreshRate];
678  auto display = flutter::Display(refresh_rate);
679  _shell->OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, {display});
680 }
681 
682 - (BOOL)run {
683  return [self runWithEntrypoint:FlutterDefaultDartEntrypoint
684  libraryURI:nil
685  initialRoute:FlutterDefaultInitialRoute];
686 }
687 
688 - (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
689  return [self runWithEntrypoint:entrypoint
690  libraryURI:libraryURI
691  initialRoute:FlutterDefaultInitialRoute];
692 }
693 
694 - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
695  return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
696 }
697 
698 - (BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
699  return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
700 }
701 
702 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
703  libraryURI:(NSString*)libraryURI
704  initialRoute:(NSString*)initialRoute {
705  if ([self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
706  [self launchEngine:entrypoint libraryURI:libraryURI];
707  }
708 
709  return _shell != nullptr;
710 }
711 
712 - (void)notifyLowMemory {
713  if (_shell) {
714  _shell->NotifyLowMemoryWarning();
715  }
716  [_systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
717 }
718 
719 #pragma mark - Text input delegate
720 
721 - (void)handlePressEvent:(FlutterUIPressProxy*)press
722  nextAction:(void (^)())next API_AVAILABLE(ios(13.4)) {
723  if (_viewController.get() != nullptr) {
724  [_viewController.get() handlePressEvent:press nextAction:next];
725  }
726 }
727 
728 - (void)updateEditingClient:(int)client withState:(NSDictionary*)state {
729  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingState"
730  arguments:@[ @(client), state ]];
731 }
732 
733 - (void)updateEditingClient:(int)client withState:(NSDictionary*)state withTag:(NSString*)tag {
734  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithTag"
735  arguments:@[ @(client), @{tag : state} ]];
736 }
737 
738 - (void)updateEditingClient:(int)client withDelta:(NSDictionary*)delta {
739  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
740  arguments:@[ @(client), delta ]];
741 }
742 
743 - (void)updateFloatingCursor:(FlutterFloatingCursorDragState)state
744  withClient:(int)client
745  withPosition:(NSDictionary*)position {
746  NSString* stateString;
747  switch (state) {
748  case FlutterFloatingCursorDragStateStart:
749  stateString = @"FloatingCursorDragState.start";
750  break;
751  case FlutterFloatingCursorDragStateUpdate:
752  stateString = @"FloatingCursorDragState.update";
753  break;
754  case FlutterFloatingCursorDragStateEnd:
755  stateString = @"FloatingCursorDragState.end";
756  break;
757  }
758  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateFloatingCursor"
759  arguments:@[ @(client), stateString, position ]];
760 }
761 
762 - (void)performAction:(FlutterTextInputAction)action withClient:(int)client {
763  NSString* actionString;
764  switch (action) {
765  case FlutterTextInputActionUnspecified:
766  // Where did the term "unspecified" come from? iOS has a "default" and Android
767  // has "unspecified." These 2 terms seem to mean the same thing but we need
768  // to pick just one. "unspecified" was chosen because "default" is often a
769  // reserved word in languages with switch statements (dart, java, etc).
770  actionString = @"TextInputAction.unspecified";
771  break;
772  case FlutterTextInputActionDone:
773  actionString = @"TextInputAction.done";
774  break;
775  case FlutterTextInputActionGo:
776  actionString = @"TextInputAction.go";
777  break;
778  case FlutterTextInputActionSend:
779  actionString = @"TextInputAction.send";
780  break;
781  case FlutterTextInputActionSearch:
782  actionString = @"TextInputAction.search";
783  break;
784  case FlutterTextInputActionNext:
785  actionString = @"TextInputAction.next";
786  break;
787  case FlutterTextInputActionContinue:
788  actionString = @"TextInputAction.continue";
789  break;
790  case FlutterTextInputActionJoin:
791  actionString = @"TextInputAction.join";
792  break;
793  case FlutterTextInputActionRoute:
794  actionString = @"TextInputAction.route";
795  break;
796  case FlutterTextInputActionEmergencyCall:
797  actionString = @"TextInputAction.emergencyCall";
798  break;
799  case FlutterTextInputActionNewline:
800  actionString = @"TextInputAction.newline";
801  break;
802  }
803  [_textInputChannel.get() invokeMethod:@"TextInputClient.performAction"
804  arguments:@[ @(client), actionString ]];
805 }
806 
807 - (void)showAutocorrectionPromptRectForStart:(NSUInteger)start
808  end:(NSUInteger)end
809  withClient:(int)client {
810  [_textInputChannel.get() invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
811  arguments:@[ @(client), @(start), @(end) ]];
812 }
813 
814 #pragma mark - FlutterViewEngineDelegate
815 
817  asBase64Encoded:(BOOL)base64Encode {
818  FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
819  return _shell->Screenshot(type, base64Encode);
820 }
821 
822 - (void)flutterViewAccessibilityDidCall {
823  if (self.viewController.view.accessibilityElements == nil) {
824  [self ensureSemanticsEnabled];
825  }
826 }
827 
828 - (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
829  return _binaryMessenger;
830 }
831 
832 // For test only. Ideally we should create a dependency injector for all dependencies and
833 // remove this.
834 - (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger {
835  // Discard the previous messenger and keep the new one.
836  _binaryMessenger.parent = nil;
837  [_binaryMessenger release];
839 }
840 
841 #pragma mark - FlutterBinaryMessenger
842 
843 - (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
844  [self sendOnChannel:channel message:message binaryReply:nil];
845 }
846 
847 - (void)sendOnChannel:(NSString*)channel
848  message:(NSData*)message
849  binaryReply:(FlutterBinaryReply)callback {
850  NSParameterAssert(channel);
851  NSAssert(_shell && _shell->IsSetup(),
852  @"Sending a message before the FlutterEngine has been run.");
854  (callback == nil) ? nullptr
855  : fml::MakeRefCounted<flutter::PlatformMessageResponseDarwin>(
856  ^(NSData* reply) {
857  callback(reply);
858  },
859  _shell->GetTaskRunners().GetPlatformTaskRunner());
860  std::unique_ptr<flutter::PlatformMessage> platformMessage =
861  (message == nil) ? std::make_unique<flutter::PlatformMessage>(channel.UTF8String, response)
862  : std::make_unique<flutter::PlatformMessage>(
863  channel.UTF8String, flutter::CopyNSDataToMapping(message), response);
864 
865  _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
866 }
867 
868 - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
869  binaryMessageHandler:
870  (FlutterBinaryMessageHandler)handler {
871  NSParameterAssert(channel);
872  if (_shell && _shell->IsSetup()) {
873  self.iosPlatformView->GetPlatformMessageRouter().SetMessageHandler(channel.UTF8String, handler);
874  return _connections->AquireConnection(channel.UTF8String);
875  } else {
876  NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
877  // Setting a handler to nil for a channel that has not yet been set up is a no-op.
879  }
880 }
881 
882 - (void)cleanupConnection:(FlutterBinaryMessengerConnection)connection {
883  if (_shell && _shell->IsSetup()) {
884  std::string channel = _connections->CleanupConnection(connection);
885  if (!channel.empty()) {
886  self.iosPlatformView->GetPlatformMessageRouter().SetMessageHandler(channel.c_str(), nil);
887  }
888  }
889 }
890 
891 #pragma mark - FlutterTextureRegistry
892 
893 - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture {
894  int64_t textureId = _nextTextureId++;
895  self.iosPlatformView->RegisterExternalTexture(textureId, texture);
896  return textureId;
897 }
898 
899 - (void)unregisterTexture:(int64_t)textureId {
900  _shell->GetPlatformView()->UnregisterTexture(textureId);
901 }
902 
903 - (void)textureFrameAvailable:(int64_t)textureId {
904  _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
905 }
906 
907 - (NSString*)lookupKeyForAsset:(NSString*)asset {
908  return [FlutterDartProject lookupKeyForAsset:asset];
909 }
910 
911 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
912  return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
913 }
914 
915 - (id<FlutterPluginRegistry>)pluginRegistry {
916  return self;
917 }
918 
919 #pragma mark - FlutterPluginRegistry
920 
921 - (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
922  NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
923  self.pluginPublications[pluginKey] = [NSNull null];
924  FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey
925  flutterEngine:self];
926  self.registrars[pluginKey] = result;
927  return [result autorelease];
928 }
929 
930 - (BOOL)hasPlugin:(NSString*)pluginKey {
931  return _pluginPublications[pluginKey] != nil;
932 }
933 
934 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
935  return _pluginPublications[pluginKey];
936 }
937 
938 #pragma mark - Notifications
939 
940 - (void)applicationWillEnterForeground:(NSNotification*)notification {
941  [self setIsGpuDisabled:NO];
942 }
943 
944 - (void)applicationDidEnterBackground:(NSNotification*)notification {
945  [self setIsGpuDisabled:YES];
946  [self notifyLowMemory];
947 }
948 
949 - (void)onMemoryWarning:(NSNotification*)notification {
950  [self notifyLowMemory];
951 }
952 
953 - (void)setIsGpuDisabled:(BOOL)value {
954  if (_shell) {
957  }
958  _isGpuDisabled = value;
959 }
960 
961 #pragma mark - Locale updates
962 
963 - (void)onLocaleUpdated:(NSNotification*)notification {
964  // Get and pass the user's preferred locale list to dart:ui.
965  NSMutableArray<NSString*>* localeData = [[[NSMutableArray alloc] init] autorelease];
966  NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
967  for (NSString* localeID in preferredLocales) {
968  NSLocale* locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease];
969  NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
970  NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
971  NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
972  NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
973  if (!languageCode) {
974  continue;
975  }
976  [localeData addObject:languageCode];
977  [localeData addObject:(countryCode ? countryCode : @"")];
978  [localeData addObject:(scriptCode ? scriptCode : @"")];
979  [localeData addObject:(variantCode ? variantCode : @"")];
980  }
981  if (localeData.count == 0) {
982  return;
983  }
984  [self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
985 }
986 
987 - (void)waitForFirstFrame:(NSTimeInterval)timeout
988  callback:(void (^_Nonnull)(BOOL didTimeout))callback {
989  dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
990  dispatch_async(queue, ^{
991  fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
992  BOOL didTimeout =
993  self.shell.WaitForFirstFrame(waitTime).code() == fml::StatusCode::kDeadlineExceeded;
994  dispatch_async(dispatch_get_main_queue(), ^{
995  callback(didTimeout);
996  });
997  });
998 }
999 
1000 - (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
1001  libraryURI:(/*nullable*/ NSString*)libraryURI
1002  initialRoute:(/*nullable*/ NSString*)initialRoute {
1003  NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
1004  FlutterEngine* result = [[FlutterEngine alloc] initWithName:_labelPrefix
1005  project:_dartProject.get()
1006  allowHeadlessExecution:_allowHeadlessExecution];
1007 
1008  flutter::RunConfiguration configuration =
1009  [_dartProject.get() runConfigurationForEntrypoint:entrypoint libraryOrNil:libraryURI];
1010 
1012  FML_DCHECK(platform_view);
1013  // Static-cast safe since this class always creates PlatformViewIOS instances.
1014  flutter::PlatformViewIOS* ios_platform_view =
1015  static_cast<flutter::PlatformViewIOS*>(platform_view.get());
1016  std::shared_ptr<flutter::IOSContext> context = ios_platform_view->GetIosContext();
1017  FML_DCHECK(context);
1018 
1019  // Lambda captures by pointers to ObjC objects are fine here because the
1020  // create call is synchronous.
1022  [result, context](flutter::Shell& shell) {
1023  [result recreatePlatformViewController];
1024  return std::make_unique<flutter::PlatformViewIOS>(
1025  shell, context, result->_platformViewsController, shell.GetTaskRunners());
1026  };
1027 
1029  [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
1030 
1031  std::string cppInitialRoute;
1032  if (initialRoute) {
1033  cppInitialRoute = [initialRoute UTF8String];
1034  }
1035 
1036  std::unique_ptr<flutter::Shell> shell = _shell->Spawn(
1037  std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1038 
1039  result->_threadHost = _threadHost;
1040  result->_profiler = _profiler;
1041  result->_profiler_metrics = _profiler_metrics;
1042  [result setupShell:std::move(shell) withObservatoryPublication:NO];
1043  return result;
1044 }
1045 
1046 - (const flutter::ThreadHost&)threadHost {
1047  return *_threadHost;
1048 }
1049 
1050 @end
1051 
1052 @implementation FlutterEngineRegistrar {
1053  NSString* _pluginKey;
1054 }
1055 
1056 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
1057  self = [super init];
1058  NSAssert(self, @"Super init cannot be nil");
1059  _pluginKey = [pluginKey copy];
1061  return self;
1062 }
1063 
1064 - (void)dealloc {
1065  [_pluginKey release];
1066  [super dealloc];
1067 }
1068 
1069 - (NSObject<FlutterBinaryMessenger>*)messenger {
1071 }
1072 
1073 - (NSObject<FlutterTextureRegistry>*)textures {
1074  return _flutterEngine;
1075 }
1076 
1077 - (void)publish:(NSObject*)value {
1078  _flutterEngine.pluginPublications[_pluginKey] = value;
1079 }
1080 
1081 - (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
1082  channel:(FlutterMethodChannel*)channel {
1083  [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1084  [delegate handleMethodCall:call result:result];
1085  }];
1086 }
1087 
1088 - (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate {
1089  id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
1090  if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifeCycleProvider)]) {
1091  id<FlutterAppLifeCycleProvider> lifeCycleProvider =
1092  (id<FlutterAppLifeCycleProvider>)appDelegate;
1093  [lifeCycleProvider addApplicationLifeCycleDelegate:delegate];
1094  }
1095 }
1096 
1097 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1098  return [_flutterEngine lookupKeyForAsset:asset];
1099 }
1100 
1101 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1102  return [_flutterEngine lookupKeyForAsset:asset fromPackage:package];
1103 }
1104 
1105 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1106  withId:(NSString*)factoryId {
1107  [self registerViewFactory:factory
1108  withId:factoryId
1109  gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
1110 }
1111 
1112 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1113  withId:(NSString*)factoryId
1114  gestureRecognizersBlockingPolicy:
1115  (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy {
1116  [_flutterEngine platformViewsController]->RegisterViewFactory(factory, factoryId,
1117  gestureRecognizersBlockingPolicy);
1118 }
1119 
1120 @end
uint64_t timestamp
Definition: key_data.h:33
BOOL forceSoftwareRendering
Definition: FlutterView.h:47
fml::scoped_nsobject< FlutterTextInputPlugin > _textInputPlugin
uint64_t synthesized
Definition: key_data.h:40
std::string advisory_script_entrypoint
Definition: settings.h:153
KeyCallType type
BOOL _allowHeadlessExecution
G_BEGIN_DECLS FlTexture * texture
Maintains a current integer assigned to a name (connections).
void handleMethodCall:result:(FlutterMethodCall *call, [result] FlutterResult result)
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition: shell.h:114
std::unique_ptr< fml::WeakPtrFactory< FlutterEngine > > _weakFactory
NSString *const FlutterEngineWillDealloc
std::shared_ptr< flutter::SamplingProfiler > _profiler
NSObject< FlutterBinaryMessenger > * binaryMessenger
#define FML_DCHECK(condition)
Definition: logging.h:86
uint64_t logical
Definition: key_data.h:36
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
std::string advisory_script_uri
Definition: settings.h:150
std::unique_ptr< flutter::Shell > _shell
fml::scoped_nsobject< FlutterBasicMessageChannel > _keyEventChannel
std::unique_ptr< flutter::ConnectionCollection > _connections
fml::scoped_nsobject< FlutterPlatformPlugin > _platformPlugin
FlutterTextInputPlugin * textInputPlugin
void reset(NST object=nil)
BOOL _restorationEnabled
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
char32_t character
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
fml::scoped_nsobject< FlutterRestorationPlugin > _restorationPlugin
GAsyncResult * result
NSString * isolateId
int64_t _nextTextureId
#define FML_LOG(severity)
Definition: logging.h:65
fml::scoped_nsobject< FlutterMethodChannel > _platformViewsChannel
fml::scoped_nsobject< UIPointerInteraction > _pointerInteraction API_AVAILABLE(ios(13.4))
fml::scoped_nsobject< FlutterObservatoryPublisher > _publisher
FlKeyEvent FlKeyResponderAsyncCallback callback
fml::scoped_nsobject< FlutterMethodChannel > _localizationChannel
FlKeyEvent * event
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
instancetype sharedInstance()
std::shared_ptr< flutter::FlutterPlatformViewsController > _platformViewsController
Indicates that GPU operations should be permitted.
A POD type used to return the screenshot data along with the size of the frame.
Definition: rasterizer.h:275
uint8_t value
T * get() const
Definition: weak_ptr.h:88
fml::MallocMapping CopyNSDataToMapping(NSData *data)
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition: rasterizer.h:245
static constexpr int kNumProfilerSamplesPerSec
Specifies all the configuration required by the runtime library to launch the root isolate...
KeyEventType type
Definition: key_data.h:34
instancetype initWithName:project:allowHeadlessExecution:restorationEnabled:(NSString *labelPrefix, [project] nullable FlutterDartProject *project, [allowHeadlessExecution] BOOL allowHeadlessExecution, [restorationEnabled] BOOL NS_DESIGNATED_INITIALIZER)
BOOL runWithEntrypoint:libraryURI:initialRoute:(nullable NSString *entrypoint, [libraryURI] nullable NSString *libraryURI, [initialRoute] nullable NSString *initialRoute)
SemanticsAction action
The collection of all the threads used by the engine.
Definition: thread_host.h:16
NSString *const FlutterDefaultDartEntrypoint
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, TaskRunners task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer, bool is_gpu_disabled=false)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
Definition: shell.cc:126
NSString * lookupKeyForAsset:fromPackage:(NSString *asset, [fromPackage] NSString *package)
fml::scoped_nsobject< FlutterMethodChannel > _platformChannel
size_t length
void ensureSemanticsEnabled()
bool EnableTracingIfNecessary(const Settings &vm_settings)
Enables tracing in the process so that JIT mode VMs may be launched. Explicitly enabling tracing is n...
Definition: ptrace_check.h:45
NSString * lookupKeyForAsset:(NSString *asset)
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
instancetype initWithName:project:allowHeadlessExecution:(NSString *labelPrefix, [project] nullable FlutterDartProject *project, [allowHeadlessExecution] BOOL allowHeadlessExecution)
FlutterPlatformViewGestureRecognizersBlockingPolicy
int BOOL
Definition: windows_types.h:37
fml::WeakPtr< FlutterViewController > _viewController
NSString * _labelPrefix
NSString *const FlutterDefaultInitialRoute
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
void sendMessage:(id _Nullable message)
uint64_t physical
Definition: key_data.h:35
fml::scoped_nsobject< FlutterMethodChannel > _textInputChannel
static Connection MakeErrorConnection(int errCode)
void(* FlutterKeyEventCallback)(bool, void *)
Definition: embedder.h:748
void handleMethodCall:result:(FlutterMethodCall *call, [result] FlutterResult result)
std::shared_ptr< flutter::ProfilerMetricsIOS > _profiler_metrics
FlutterBasicMessageChannel * lifecycleChannel
int64_t FlutterBinaryMessengerConnection
fml::scoped_nsobject< FlutterBasicMessageChannel > _lifecycleChannel
std::shared_ptr< flutter::ThreadHost > _threadHost
fml::scoped_nsobject< FlutterMethodChannel > _restorationChannel
flutter::IOSRenderingAPI _renderingApi
const std::shared_ptr< IOSContext > & GetIosContext()
bool enable_software_rendering
Definition: settings.h:248
void SetOwnerViewController(fml::WeakPtr< FlutterViewController > owner_controller)
FlutterBinaryMessengerRelay * _binaryMessenger
AtkStateType state
fml::scoped_nsobject< FlutterBasicMessageChannel > _systemChannel
NSObject< FlutterBinaryMessenger > * parent
fml::scoped_nsobject< FlutterMethodChannel > _navigationChannel
FlutterViewController * viewController
FlutterEngine * flutterEngine
FlutterEngine * _flutterEngine
fml::scoped_nsobject< FlutterBasicMessageChannel > _settingsChannel