Flutter iOS Embedder
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 
8 
9 #include <memory>
10 
11 #include "flutter/common/constants.h"
12 #include "flutter/fml/message_loop.h"
13 #include "flutter/fml/platform/darwin/platform_version.h"
14 #include "flutter/fml/platform/darwin/weak_nsobject.h"
15 #include "flutter/fml/trace_event.h"
16 #include "flutter/runtime/ptrace_check.h"
17 #include "flutter/shell/common/engine.h"
18 #include "flutter/shell/common/platform_view.h"
19 #include "flutter/shell/common/shell.h"
20 #include "flutter/shell/common/switches.h"
21 #include "flutter/shell/common/thread_host.h"
22 #include "flutter/shell/common/variable_refresh_rate_display.h"
42 #include "flutter/shell/profiling/sampling_profiler.h"
43 
44 /// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities
45 /// Using iOS platform thread API to configure thread priority
46 static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig& config) {
47  // set thread name
48  fml::Thread::SetCurrentThreadName(config);
49 
50  // set thread priority
51  switch (config.priority) {
52  case fml::Thread::ThreadPriority::kBackground: {
53  pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
54  [[NSThread currentThread] setThreadPriority:0];
55  break;
56  }
57  case fml::Thread::ThreadPriority::kNormal: {
58  pthread_set_qos_class_self_np(QOS_CLASS_DEFAULT, 0);
59  [[NSThread currentThread] setThreadPriority:0.5];
60  break;
61  }
62  case fml::Thread::ThreadPriority::kRaster:
63  case fml::Thread::ThreadPriority::kDisplay: {
64  pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
65  [[NSThread currentThread] setThreadPriority:1.0];
66  sched_param param;
67  int policy;
68  pthread_t thread = pthread_self();
69  if (!pthread_getschedparam(thread, &policy, &param)) {
70  param.sched_priority = 50;
71  pthread_setschedparam(thread, policy, &param);
72  }
73  break;
74  }
75  }
76 }
77 
78 #pragma mark - Public exported constants
79 
80 NSString* const FlutterDefaultDartEntrypoint = nil;
81 NSString* const FlutterDefaultInitialRoute = nil;
82 
83 #pragma mark - Internal constants
84 
85 NSString* const kFlutterEngineWillDealloc = @"FlutterEngineWillDealloc";
86 NSString* const kFlutterKeyDataChannel = @"flutter/keydata";
87 static constexpr int kNumProfilerSamplesPerSec = 5;
88 
90 @property(nonatomic, assign) FlutterEngine* flutterEngine;
91 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
92 @end
93 
99 // Maintains a dictionary of plugin names that have registered with the engine. Used by
100 // FlutterEngineRegistrar to implement a FlutterPluginRegistrar.
101 @property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
102 @property(nonatomic, readonly) NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* registrars;
103 
104 @property(nonatomic, readwrite, copy) NSString* isolateId;
105 @property(nonatomic, copy) NSString* initialRoute;
106 @property(nonatomic, retain) id<NSObject> flutterViewControllerWillDeallocObserver;
107 
108 #pragma mark - Embedder API properties
109 
110 @property(nonatomic, assign) BOOL enableEmbedderAPI;
111 // Function pointers for interacting with the embedder.h API.
112 @property(nonatomic) FlutterEngineProcTable& embedderAPI;
113 @end
114 
115 @implementation FlutterEngine {
116  fml::scoped_nsobject<FlutterDartProject> _dartProject;
117  std::shared_ptr<flutter::ThreadHost> _threadHost;
118  std::unique_ptr<flutter::Shell> _shell;
119  NSString* _labelPrefix;
120  std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory;
121 
122  fml::WeakNSObject<FlutterViewController> _viewController;
123  fml::scoped_nsobject<FlutterDartVMServicePublisher> _publisher;
124 
125  std::shared_ptr<flutter::FlutterPlatformViewsController> _platformViewsController;
127  std::shared_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
128  std::shared_ptr<flutter::SamplingProfiler> _profiler;
129 
130  // Channels
131  fml::scoped_nsobject<FlutterPlatformPlugin> _platformPlugin;
132  fml::scoped_nsobject<FlutterTextInputPlugin> _textInputPlugin;
133  fml::scoped_nsobject<FlutterUndoManagerPlugin> _undoManagerPlugin;
134  fml::scoped_nsobject<FlutterSpellCheckPlugin> _spellCheckPlugin;
135  fml::scoped_nsobject<FlutterRestorationPlugin> _restorationPlugin;
136  fml::scoped_nsobject<FlutterMethodChannel> _localizationChannel;
137  fml::scoped_nsobject<FlutterMethodChannel> _navigationChannel;
138  fml::scoped_nsobject<FlutterMethodChannel> _restorationChannel;
139  fml::scoped_nsobject<FlutterMethodChannel> _platformChannel;
140  fml::scoped_nsobject<FlutterMethodChannel> _platformViewsChannel;
141  fml::scoped_nsobject<FlutterMethodChannel> _textInputChannel;
142  fml::scoped_nsobject<FlutterMethodChannel> _undoManagerChannel;
143  fml::scoped_nsobject<FlutterMethodChannel> _scribbleChannel;
144  fml::scoped_nsobject<FlutterMethodChannel> _spellCheckChannel;
145  fml::scoped_nsobject<FlutterBasicMessageChannel> _lifecycleChannel;
146  fml::scoped_nsobject<FlutterBasicMessageChannel> _systemChannel;
147  fml::scoped_nsobject<FlutterBasicMessageChannel> _settingsChannel;
148  fml::scoped_nsobject<FlutterBasicMessageChannel> _keyEventChannel;
149  fml::scoped_nsobject<FlutterMethodChannel> _screenshotChannel;
150 
151  int64_t _nextTextureId;
152 
157  std::unique_ptr<flutter::ConnectionCollection> _connections;
158 }
159 
160 - (instancetype)init {
161  return [self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
162 }
163 
164 - (instancetype)initWithName:(NSString*)labelPrefix {
165  return [self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
166 }
167 
168 - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
169  return [self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
170 }
171 
172 - (instancetype)initWithName:(NSString*)labelPrefix
173  project:(FlutterDartProject*)project
174  allowHeadlessExecution:(BOOL)allowHeadlessExecution {
175  return [self initWithName:labelPrefix
176  project:project
177  allowHeadlessExecution:allowHeadlessExecution
178  restorationEnabled:NO];
179 }
180 
181 - (instancetype)initWithName:(NSString*)labelPrefix
182  project:(FlutterDartProject*)project
183  allowHeadlessExecution:(BOOL)allowHeadlessExecution
184  restorationEnabled:(BOOL)restorationEnabled {
185  self = [super init];
186  NSAssert(self, @"Super init cannot be nil");
187  NSAssert(labelPrefix, @"labelPrefix is required");
188 
189  _restorationEnabled = restorationEnabled;
190  _allowHeadlessExecution = allowHeadlessExecution;
191  _labelPrefix = [labelPrefix copy];
192 
193  _weakFactory = std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(self);
194 
195  if (project == nil) {
196  _dartProject.reset([[FlutterDartProject alloc] init]);
197  } else {
198  _dartProject.reset([project retain]);
199  }
200 
201  _enableEmbedderAPI = _dartProject.get().settings.enable_embedder_api;
202  if (_enableEmbedderAPI) {
203  NSLog(@"============== iOS: enable_embedder_api is on ==============");
204  _embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
205  FlutterEngineGetProcAddresses(&_embedderAPI);
206  }
207 
208  if (!EnableTracingIfNecessary([_dartProject.get() settings])) {
209  NSLog(
210  @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
211  @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
212  @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
213  @"profile and release mode apps can be launched from the home screen.");
214  [self release];
215  return nil;
216  }
217 
218  _pluginPublications = [[NSMutableDictionary alloc] init];
219  _registrars = [[NSMutableDictionary alloc] init];
220  [self recreatePlatformViewController];
221 
222  _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
223  _textureRegistry = [[FlutterTextureRegistryRelay alloc] initWithParent:self];
225 
226  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
227  [center addObserver:self
228  selector:@selector(onMemoryWarning:)
229  name:UIApplicationDidReceiveMemoryWarningNotification
230  object:nil];
231 
232 #if APPLICATION_EXTENSION_API_ONLY
233  if (@available(iOS 13.0, *)) {
234  [self setUpSceneLifecycleNotifications:center];
235  } else {
236  [self setUpApplicationLifecycleNotifications:center];
237  }
238 #else
239  [self setUpApplicationLifecycleNotifications:center];
240 #endif
241 
242  [center addObserver:self
243  selector:@selector(onLocaleUpdated:)
244  name:NSCurrentLocaleDidChangeNotification
245  object:nil];
246 
247  return self;
248 }
249 
250 - (void)setUpSceneLifecycleNotifications:(NSNotificationCenter*)center API_AVAILABLE(ios(13.0)) {
251  [center addObserver:self
252  selector:@selector(sceneWillEnterForeground:)
253  name:UISceneWillEnterForegroundNotification
254  object:nil];
255  [center addObserver:self
256  selector:@selector(sceneDidEnterBackground:)
257  name:UISceneDidEnterBackgroundNotification
258  object:nil];
259 }
260 
261 - (void)setUpApplicationLifecycleNotifications:(NSNotificationCenter*)center {
262  [center addObserver:self
263  selector:@selector(applicationWillEnterForeground:)
264  name:UIApplicationWillEnterForegroundNotification
265  object:nil];
266  [center addObserver:self
267  selector:@selector(applicationDidEnterBackground:)
268  name:UIApplicationDidEnterBackgroundNotification
269  object:nil];
270 }
271 
272 - (void)recreatePlatformViewController {
275 }
276 
277 - (flutter::IOSRenderingAPI)platformViewsRenderingAPI {
278  return _renderingApi;
279 }
280 
281 - (void)dealloc {
282  /// Notify plugins of dealloc. This should happen first in dealloc since the
283  /// plugins may be talking to things like the binaryMessenger.
284  [_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
285  if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
286  NSObject<FlutterPluginRegistrar>* registrar = self.registrars[key];
287  [object detachFromEngineForRegistrar:registrar];
288  }
289  }];
290 
291  [[NSNotificationCenter defaultCenter] postNotificationName:kFlutterEngineWillDealloc
292  object:self
293  userInfo:nil];
294 
295  // It will be destroyed and invalidate its weak pointers
296  // before any other members are destroyed.
297  _weakFactory.reset();
298 
299  /// nil out weak references.
300  [_registrars
301  enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) {
302  registrar.flutterEngine = nil;
303  }];
304 
305  [_labelPrefix release];
306  [_initialRoute release];
307  [_pluginPublications release];
308  [_registrars release];
309  _binaryMessenger.parent = nil;
310  _textureRegistry.parent = nil;
311  [_binaryMessenger release];
312  [_textureRegistry release];
313  _textureRegistry = nil;
314  [_isolateId release];
315 
316  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
317  if (_flutterViewControllerWillDeallocObserver) {
318  [center removeObserver:_flutterViewControllerWillDeallocObserver];
319  [_flutterViewControllerWillDeallocObserver release];
320  }
321  [center removeObserver:self];
322 
323  [super dealloc];
324 }
325 
326 - (flutter::Shell&)shell {
327  FML_DCHECK(_shell);
328  return *_shell;
329 }
330 
331 - (fml::WeakNSObject<FlutterEngine>)getWeakNSObject {
332  return _weakFactory->GetWeakNSObject();
333 }
334 
335 - (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics {
336  if (!self.platformView) {
337  return;
338  }
339  self.platformView->SetViewportMetrics(flutter::kFlutterImplicitViewId, viewportMetrics);
340 }
341 
342 - (void)dispatchPointerDataPacket:(std::unique_ptr<flutter::PointerDataPacket>)packet {
343  if (!self.platformView) {
344  return;
345  }
346  self.platformView->DispatchPointerDataPacket(std::move(packet));
347 }
348 
349 - (fml::WeakPtr<flutter::PlatformView>)platformView {
350  FML_DCHECK(_shell);
351  return _shell->GetPlatformView();
352 }
353 
354 - (flutter::PlatformViewIOS*)iosPlatformView {
355  FML_DCHECK(_shell);
356  return static_cast<flutter::PlatformViewIOS*>(_shell->GetPlatformView().get());
357 }
358 
359 - (fml::RefPtr<fml::TaskRunner>)platformTaskRunner {
360  FML_DCHECK(_shell);
361  return _shell->GetTaskRunners().GetPlatformTaskRunner();
362 }
363 
364 - (fml::RefPtr<fml::TaskRunner>)uiTaskRunner {
365  FML_DCHECK(_shell);
366  return _shell->GetTaskRunners().GetUITaskRunner();
367 }
368 
369 - (fml::RefPtr<fml::TaskRunner>)rasterTaskRunner {
370  FML_DCHECK(_shell);
371  return _shell->GetTaskRunners().GetRasterTaskRunner();
372 }
373 
374 - (void)sendKeyEvent:(const FlutterKeyEvent&)event
375  callback:(FlutterKeyEventCallback)callback
376  userData:(void*)userData API_AVAILABLE(ios(13.4)) {
377  if (@available(iOS 13.4, *)) {
378  } else {
379  return;
380  }
381  if (!self.platformView) {
382  return;
383  }
384  const char* character = event.character;
385 
386  flutter::KeyData key_data;
387  key_data.Clear();
388  key_data.timestamp = (uint64_t)event.timestamp;
389  switch (event.type) {
390  case kFlutterKeyEventTypeUp:
391  key_data.type = flutter::KeyEventType::kUp;
392  break;
393  case kFlutterKeyEventTypeDown:
394  key_data.type = flutter::KeyEventType::kDown;
395  break;
396  case kFlutterKeyEventTypeRepeat:
397  key_data.type = flutter::KeyEventType::kRepeat;
398  break;
399  }
400  key_data.physical = event.physical;
401  key_data.logical = event.logical;
402  key_data.synthesized = event.synthesized;
403 
404  auto packet = std::make_unique<flutter::KeyDataPacket>(key_data, character);
405  NSData* message = [NSData dataWithBytes:packet->data().data() length:packet->data().size()];
406 
407  auto response = ^(NSData* reply) {
408  if (callback == nullptr) {
409  return;
410  }
411  BOOL handled = FALSE;
412  if (reply.length == 1 && *reinterpret_cast<const uint8_t*>(reply.bytes) == 1) {
413  handled = TRUE;
414  }
415  callback(handled, userData);
416  };
417 
418  [self sendOnChannel:kFlutterKeyDataChannel message:message binaryReply:response];
419 }
420 
421 - (void)ensureSemanticsEnabled {
422  self.iosPlatformView->SetSemanticsEnabled(true);
423 }
424 
425 - (void)setViewController:(FlutterViewController*)viewController {
426  FML_DCHECK(self.iosPlatformView);
427  _viewController = viewController ? [viewController getWeakNSObject]
428  : fml::WeakNSObject<FlutterViewController>();
429  self.iosPlatformView->SetOwnerViewController(_viewController);
430  [self maybeSetupPlatformViewChannels];
431  [self updateDisplays];
432  _textInputPlugin.get().viewController = viewController;
433 
434  if (viewController) {
435  __block FlutterEngine* blockSelf = self;
436  self.flutterViewControllerWillDeallocObserver =
437  [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
438  object:viewController
439  queue:[NSOperationQueue mainQueue]
440  usingBlock:^(NSNotification* note) {
441  [blockSelf notifyViewControllerDeallocated];
442  }];
443  } else {
444  self.flutterViewControllerWillDeallocObserver = nil;
445  [self notifyLowMemory];
446  }
447 }
448 
449 - (void)attachView {
450  self.iosPlatformView->attachView();
451 }
452 
453 - (void)setFlutterViewControllerWillDeallocObserver:(id<NSObject>)observer {
454  if (observer != _flutterViewControllerWillDeallocObserver) {
455  if (_flutterViewControllerWillDeallocObserver) {
456  [[NSNotificationCenter defaultCenter]
457  removeObserver:_flutterViewControllerWillDeallocObserver];
458  [_flutterViewControllerWillDeallocObserver release];
459  }
460  _flutterViewControllerWillDeallocObserver = [observer retain];
461  }
462 }
463 
464 - (void)notifyViewControllerDeallocated {
465  [[self lifecycleChannel] sendMessage:@"AppLifecycleState.detached"];
466  _textInputPlugin.get().viewController = nil;
468  [self destroyContext];
469  } else if (_shell) {
470  flutter::PlatformViewIOS* platform_view = [self iosPlatformView];
471  if (platform_view) {
472  platform_view->SetOwnerViewController({});
473  }
474  }
475  [_textInputPlugin.get() resetViewResponder];
476  _viewController.reset();
477 }
478 
479 - (void)destroyContext {
480  [self resetChannels];
481  self.isolateId = nil;
482  _shell.reset();
483  _profiler.reset();
484  _threadHost.reset();
485  _platformViewsController.reset();
486 }
487 
489  if (!_viewController) {
490  return nil;
491  }
492  return _viewController.get();
493 }
494 
495 - (FlutterPlatformPlugin*)platformPlugin {
496  return _platformPlugin.get();
497 }
498 - (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController {
500 }
502  return _textInputPlugin.get();
503 }
504 - (FlutterUndoManagerPlugin*)undoManagerPlugin {
505  return _undoManagerPlugin.get();
506 }
507 - (FlutterRestorationPlugin*)restorationPlugin {
508  return _restorationPlugin.get();
509 }
510 - (FlutterMethodChannel*)localizationChannel {
511  return _localizationChannel.get();
512 }
513 - (FlutterMethodChannel*)navigationChannel {
514  return _navigationChannel.get();
515 }
516 - (FlutterMethodChannel*)restorationChannel {
517  return _restorationChannel.get();
518 }
519 - (FlutterMethodChannel*)platformChannel {
520  return _platformChannel.get();
521 }
522 - (FlutterMethodChannel*)textInputChannel {
523  return _textInputChannel.get();
524 }
525 - (FlutterMethodChannel*)undoManagerChannel {
526  return _undoManagerChannel.get();
527 }
528 - (FlutterMethodChannel*)scribbleChannel {
529  return _scribbleChannel.get();
530 }
531 - (FlutterMethodChannel*)spellCheckChannel {
532  return _spellCheckChannel.get();
533 }
534 - (FlutterBasicMessageChannel*)lifecycleChannel {
535  return _lifecycleChannel.get();
536 }
537 - (FlutterBasicMessageChannel*)systemChannel {
538  return _systemChannel.get();
539 }
540 - (FlutterBasicMessageChannel*)settingsChannel {
541  return _settingsChannel.get();
542 }
543 - (FlutterBasicMessageChannel*)keyEventChannel {
544  return _keyEventChannel.get();
545 }
546 
547 - (NSURL*)observatoryUrl {
548  return [_publisher.get() url];
549 }
550 
551 - (NSURL*)vmServiceUrl {
552  return [_publisher.get() url];
553 }
554 
555 - (void)resetChannels {
556  _localizationChannel.reset();
557  _navigationChannel.reset();
558  _restorationChannel.reset();
559  _platformChannel.reset();
560  _platformViewsChannel.reset();
561  _textInputChannel.reset();
562  _undoManagerChannel.reset();
563  _scribbleChannel.reset();
564  _lifecycleChannel.reset();
565  _systemChannel.reset();
566  _settingsChannel.reset();
567  _keyEventChannel.reset();
568  _spellCheckChannel.reset();
569 }
570 
571 - (void)startProfiler {
572  FML_DCHECK(!_threadHost->name_prefix.empty());
573  _profiler_metrics = std::make_shared<flutter::ProfilerMetricsIOS>();
574  _profiler = std::make_shared<flutter::SamplingProfiler>(
575  _threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(),
576  [self]() { return self->_profiler_metrics->GenerateSample(); }, kNumProfilerSamplesPerSec);
577  _profiler->Start();
578 }
579 
580 // If you add a channel, be sure to also update `resetChannels`.
581 // Channels get a reference to the engine, and therefore need manual
582 // cleanup for proper collection.
583 - (void)setUpChannels {
584  // This will be invoked once the shell is done setting up and the isolate ID
585  // for the UI isolate is available.
586  fml::WeakNSObject<FlutterEngine> weakSelf = [self getWeakNSObject];
587  [_binaryMessenger setMessageHandlerOnChannel:@"flutter/isolate"
588  binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
589  if (weakSelf) {
590  weakSelf.get().isolateId =
591  [[FlutterStringCodec sharedInstance] decode:message];
592  }
593  }];
594 
596  initWithName:@"flutter/localization"
597  binaryMessenger:self.binaryMessenger
598  codec:[FlutterJSONMethodCodec sharedInstance]]);
599 
601  initWithName:@"flutter/navigation"
602  binaryMessenger:self.binaryMessenger
603  codec:[FlutterJSONMethodCodec sharedInstance]]);
604 
605  if ([_initialRoute length] > 0) {
606  // Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
607  [_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
608  [_initialRoute release];
609  _initialRoute = nil;
610  }
611 
613  initWithName:@"flutter/restoration"
614  binaryMessenger:self.binaryMessenger
615  codec:[FlutterStandardMethodCodec sharedInstance]]);
616 
618  initWithName:@"flutter/platform"
619  binaryMessenger:self.binaryMessenger
620  codec:[FlutterJSONMethodCodec sharedInstance]]);
621 
623  initWithName:@"flutter/platform_views"
624  binaryMessenger:self.binaryMessenger
625  codec:[FlutterStandardMethodCodec sharedInstance]]);
626 
628  initWithName:@"flutter/textinput"
629  binaryMessenger:self.binaryMessenger
630  codec:[FlutterJSONMethodCodec sharedInstance]]);
631 
633  initWithName:@"flutter/undomanager"
634  binaryMessenger:self.binaryMessenger
635  codec:[FlutterJSONMethodCodec sharedInstance]]);
636 
638  initWithName:@"flutter/scribble"
639  binaryMessenger:self.binaryMessenger
640  codec:[FlutterJSONMethodCodec sharedInstance]]);
641 
643  initWithName:@"flutter/spellcheck"
644  binaryMessenger:self.binaryMessenger
645  codec:[FlutterStandardMethodCodec sharedInstance]]);
646 
648  initWithName:@"flutter/lifecycle"
649  binaryMessenger:self.binaryMessenger
650  codec:[FlutterStringCodec sharedInstance]]);
651 
653  initWithName:@"flutter/system"
654  binaryMessenger:self.binaryMessenger
655  codec:[FlutterJSONMessageCodec sharedInstance]]);
656 
658  initWithName:@"flutter/settings"
659  binaryMessenger:self.binaryMessenger
660  codec:[FlutterJSONMessageCodec sharedInstance]]);
661 
663  initWithName:@"flutter/keyevent"
664  binaryMessenger:self.binaryMessenger
665  codec:[FlutterJSONMessageCodec sharedInstance]]);
666 
667  FlutterTextInputPlugin* textInputPlugin = [[FlutterTextInputPlugin alloc] initWithDelegate:self];
670  [textInputPlugin setUpIndirectScribbleInteraction:self.viewController];
671 
672  FlutterUndoManagerPlugin* undoManagerPlugin =
673  [[FlutterUndoManagerPlugin alloc] initWithDelegate:self];
674  _undoManagerPlugin.reset(undoManagerPlugin);
675 
676  _platformPlugin.reset([[FlutterPlatformPlugin alloc] initWithEngine:[self getWeakNSObject]]);
677 
679  initWithChannel:_restorationChannel.get()
680  restorationEnabled:_restorationEnabled]);
681  _spellCheckPlugin.reset([[FlutterSpellCheckPlugin alloc] init]);
682 
684  initWithName:@"flutter/screenshot"
685  binaryMessenger:self.binaryMessenger
686  codec:[FlutterStandardMethodCodec sharedInstance]]);
687 
688  [_screenshotChannel.get()
689  setMethodCallHandler:^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) {
690  if (!(weakSelf.get() && weakSelf.get()->_shell && weakSelf.get()->_shell->IsSetup())) {
691  return result([FlutterError
692  errorWithCode:@"invalid_state"
693  message:@"Requesting screenshot while engine is not running."
694  details:nil]);
695  }
696  flutter::Rasterizer::Screenshot screenshot =
697  [weakSelf.get() screenshot:flutter::Rasterizer::ScreenshotType::SurfaceData
698  base64Encode:NO];
699  if (!screenshot.data) {
700  return result([FlutterError errorWithCode:@"failure"
701  message:@"Unable to get screenshot."
702  details:nil]);
703  }
704  // TODO(gaaclarke): Find way to eliminate this data copy.
705  NSData* data = [NSData dataWithBytes:screenshot.data->writable_data()
706  length:screenshot.data->size()];
707  NSString* format = [NSString stringWithUTF8String:screenshot.format.c_str()];
708  NSNumber* width = @(screenshot.frame_size.fWidth);
709  NSNumber* height = @(screenshot.frame_size.fHeight);
710  return result(@[ width, height, format ?: [NSNull null], data ]);
711  }];
712 }
713 
714 - (void)maybeSetupPlatformViewChannels {
715  if (_shell && self.shell.IsSetup()) {
716  FlutterPlatformPlugin* platformPlugin = _platformPlugin.get();
717  [_platformChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
718  [platformPlugin handleMethodCall:call result:result];
719  }];
720 
721  fml::WeakNSObject<FlutterEngine> weakSelf = [self getWeakNSObject];
722  [_platformViewsChannel.get()
723  setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
724  if (weakSelf) {
725  weakSelf.get().platformViewsController->OnMethodCall(call, result);
726  }
727  }];
728 
730  [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
731  [textInputPlugin handleMethodCall:call result:result];
732  }];
733 
734  FlutterUndoManagerPlugin* undoManagerPlugin = _undoManagerPlugin.get();
735  [_undoManagerChannel.get()
736  setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
737  [undoManagerPlugin handleMethodCall:call result:result];
738  }];
739 
740  FlutterSpellCheckPlugin* spellCheckPlugin = _spellCheckPlugin.get();
741  [_spellCheckChannel.get()
742  setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
743  [spellCheckPlugin handleMethodCall:call result:result];
744  }];
745  }
746 }
747 
748 - (flutter::Rasterizer::Screenshot)screenshot:(flutter::Rasterizer::ScreenshotType)type
749  base64Encode:(bool)base64Encode {
750  return self.shell.Screenshot(type, base64Encode);
751 }
752 
753 - (void)launchEngine:(NSString*)entrypoint
754  libraryURI:(NSString*)libraryOrNil
755  entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
756  // Launch the Dart application with the inferred run configuration.
757  self.shell.RunEngine([_dartProject.get() runConfigurationForEntrypoint:entrypoint
758  libraryOrNil:libraryOrNil
759  entrypointArgs:entrypointArgs]);
760 }
761 
762 - (void)setUpShell:(std::unique_ptr<flutter::Shell>)shell
763  withVMServicePublication:(BOOL)doesVMServicePublication {
764  _shell = std::move(shell);
765  [self setUpChannels];
766  [self onLocaleUpdated:nil];
767  [self updateDisplays];
769  initWithEnableVMServicePublication:doesVMServicePublication]);
770  [self maybeSetupPlatformViewChannels];
771  _shell->SetGpuAvailability(_isGpuDisabled ? flutter::GpuAvailability::kUnavailable
772  : flutter::GpuAvailability::kAvailable);
773 }
774 
775 + (BOOL)isProfilerEnabled {
776  bool profilerEnabled = false;
777 #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
778  (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
779  profilerEnabled = true;
780 #endif
781  return profilerEnabled;
782 }
783 
784 + (NSString*)generateThreadLabel:(NSString*)labelPrefix {
785  static size_t s_shellCount = 0;
786  return [NSString stringWithFormat:@"%@.%zu", labelPrefix, ++s_shellCount];
787 }
788 
789 + (flutter::ThreadHost)makeThreadHost:(NSString*)threadLabel {
790  // The current thread will be used as the platform thread. Ensure that the message loop is
791  // initialized.
792  fml::MessageLoop::EnsureInitializedForCurrentThread();
793 
794  uint32_t threadHostType = flutter::ThreadHost::Type::kUi | flutter::ThreadHost::Type::kRaster |
795  flutter::ThreadHost::Type::kIo;
796 
797  if ([FlutterEngine isProfilerEnabled]) {
798  threadHostType = threadHostType | flutter::ThreadHost::Type::kProfiler;
799  }
800 
801  flutter::ThreadHost::ThreadHostConfig host_config(threadLabel.UTF8String, threadHostType,
803 
804  host_config.ui_config =
805  fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
806  flutter::ThreadHost::Type::kUi, threadLabel.UTF8String),
807  fml::Thread::ThreadPriority::kDisplay);
808 
809  host_config.raster_config =
810  fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
811  flutter::ThreadHost::Type::kRaster, threadLabel.UTF8String),
812  fml::Thread::ThreadPriority::kRaster);
813 
814  host_config.io_config =
815  fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
816  flutter::ThreadHost::Type::kIo, threadLabel.UTF8String),
817  fml::Thread::ThreadPriority::kNormal);
818 
819  return (flutter::ThreadHost){host_config};
820 }
821 
822 static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
823  if (libraryURI) {
824  FML_DCHECK(entrypoint) << "Must specify entrypoint if specifying library";
825  settings->advisory_script_entrypoint = entrypoint.UTF8String;
826  settings->advisory_script_uri = libraryURI.UTF8String;
827  } else if (entrypoint) {
828  settings->advisory_script_entrypoint = entrypoint.UTF8String;
829  settings->advisory_script_uri = std::string("main.dart");
830  } else {
831  settings->advisory_script_entrypoint = std::string("main");
832  settings->advisory_script_uri = std::string("main.dart");
833  }
834 }
835 
836 - (BOOL)createShell:(NSString*)entrypoint
837  libraryURI:(NSString*)libraryURI
838  initialRoute:(NSString*)initialRoute {
839  if (_shell != nullptr) {
840  FML_LOG(WARNING) << "This FlutterEngine was already invoked.";
841  return NO;
842  }
843 
844  self.initialRoute = initialRoute;
845 
846  auto settings = [_dartProject.get() settings];
847  if (initialRoute != nil) {
848  self.initialRoute = initialRoute;
849  } else if (settings.route.empty() == false) {
850  self.initialRoute = [NSString stringWithUTF8String:settings.route.c_str()];
851  }
852 
853  FlutterView.forceSoftwareRendering = settings.enable_software_rendering;
854 
855  auto platformData = [_dartProject.get() defaultPlatformData];
856 
857  SetEntryPoint(&settings, entrypoint, libraryURI);
858 
859  NSString* threadLabel = [FlutterEngine generateThreadLabel:_labelPrefix];
860  _threadHost = std::make_shared<flutter::ThreadHost>();
861  *_threadHost = [FlutterEngine makeThreadHost:threadLabel];
862 
863  // Lambda captures by pointers to ObjC objects are fine here because the
864  // create call is synchronous.
865  flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
866  [self](flutter::Shell& shell) {
867  [self recreatePlatformViewController];
868  return std::make_unique<flutter::PlatformViewIOS>(
869  shell, self->_renderingApi, self->_platformViewsController, shell.GetTaskRunners(),
870  shell.GetConcurrentWorkerTaskRunner(), shell.GetIsGpuDisabledSyncSwitch());
871  };
872 
873  flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
874  [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
875 
876  flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
877  fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
878  _threadHost->raster_thread->GetTaskRunner(), // raster
879  _threadHost->ui_thread->GetTaskRunner(), // ui
880  _threadHost->io_thread->GetTaskRunner() // io
881  );
882 
883 #if APPLICATION_EXTENSION_API_ONLY
884  if (@available(iOS 13.0, *)) {
885  _isGpuDisabled = self.viewController.flutterWindowSceneIfViewLoaded.activationState ==
886  UISceneActivationStateBackground;
887  } else {
888  // [UIApplication sharedApplication API is not available for app extension.
889  // We intialize the shell assuming the GPU is required.
890  _isGpuDisabled = NO;
891  }
892 #else
893  _isGpuDisabled =
894  [UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
895 #endif
896 
897  // Create the shell. This is a blocking operation.
898  std::unique_ptr<flutter::Shell> shell = flutter::Shell::Create(
899  /*platform_data=*/platformData,
900  /*task_runners=*/task_runners,
901  /*settings=*/settings,
902  /*on_create_platform_view=*/on_create_platform_view,
903  /*on_create_rasterizer=*/on_create_rasterizer,
904  /*is_gpu_disabled=*/_isGpuDisabled);
905 
906  if (shell == nullptr) {
907  FML_LOG(ERROR) << "Could not start a shell FlutterEngine with entrypoint: "
908  << entrypoint.UTF8String;
909  } else {
910  // TODO(vashworth): Remove once done debugging https://github.com/flutter/flutter/issues/129836
911  FML_LOG(INFO) << "Enabled VM Service Publication: " << settings.enable_vm_service_publication;
912  [self setUpShell:std::move(shell)
913  withVMServicePublication:settings.enable_vm_service_publication];
914  if ([FlutterEngine isProfilerEnabled]) {
915  [self startProfiler];
916  }
917  }
918 
919  return _shell != nullptr;
920 }
921 
922 - (void)updateDisplays {
923  if (!_shell) {
924  // Tests may do this.
925  return;
926  }
927  auto vsync_waiter = _shell->GetVsyncWaiter().lock();
928  auto vsync_waiter_ios = std::static_pointer_cast<flutter::VsyncWaiterIOS>(vsync_waiter);
929  std::vector<std::unique_ptr<flutter::Display>> displays;
930  auto screen_size = UIScreen.mainScreen.nativeBounds.size;
931  auto scale = UIScreen.mainScreen.scale;
932  displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(
933  0, vsync_waiter_ios, screen_size.width, screen_size.height, scale));
934  _shell->OnDisplayUpdates(std::move(displays));
935 }
936 
937 - (BOOL)run {
938  return [self runWithEntrypoint:FlutterDefaultDartEntrypoint
939  libraryURI:nil
940  initialRoute:FlutterDefaultInitialRoute];
941 }
942 
943 - (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
944  return [self runWithEntrypoint:entrypoint
945  libraryURI:libraryURI
946  initialRoute:FlutterDefaultInitialRoute];
947 }
948 
949 - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
950  return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
951 }
952 
953 - (BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
954  return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
955 }
956 
957 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
958  libraryURI:(NSString*)libraryURI
959  initialRoute:(NSString*)initialRoute {
960  return [self runWithEntrypoint:entrypoint
961  libraryURI:libraryURI
962  initialRoute:initialRoute
963  entrypointArgs:nil];
964 }
965 
966 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
967  libraryURI:(NSString*)libraryURI
968  initialRoute:(NSString*)initialRoute
969  entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
970  if ([self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
971  [self launchEngine:entrypoint libraryURI:libraryURI entrypointArgs:entrypointArgs];
972  }
973 
974  return _shell != nullptr;
975 }
976 
977 - (void)notifyLowMemory {
978  if (_shell) {
979  _shell->NotifyLowMemoryWarning();
980  }
981  [_systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
982 }
983 
984 #pragma mark - Text input delegate
985 
986 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
987  updateEditingClient:(int)client
988  withState:(NSDictionary*)state {
989  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingState"
990  arguments:@[ @(client), state ]];
991 }
992 
993 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
994  updateEditingClient:(int)client
995  withState:(NSDictionary*)state
996  withTag:(NSString*)tag {
997  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithTag"
998  arguments:@[ @(client), @{tag : state} ]];
999 }
1000 
1001 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1002  updateEditingClient:(int)client
1003  withDelta:(NSDictionary*)delta {
1004  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
1005  arguments:@[ @(client), delta ]];
1006 }
1007 
1008 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1009  updateFloatingCursor:(FlutterFloatingCursorDragState)state
1010  withClient:(int)client
1011  withPosition:(NSDictionary*)position {
1012  NSString* stateString;
1013  switch (state) {
1014  case FlutterFloatingCursorDragStateStart:
1015  stateString = @"FloatingCursorDragState.start";
1016  break;
1017  case FlutterFloatingCursorDragStateUpdate:
1018  stateString = @"FloatingCursorDragState.update";
1019  break;
1020  case FlutterFloatingCursorDragStateEnd:
1021  stateString = @"FloatingCursorDragState.end";
1022  break;
1023  }
1024  [_textInputChannel.get() invokeMethod:@"TextInputClient.updateFloatingCursor"
1025  arguments:@[ @(client), stateString, position ]];
1026 }
1027 
1028 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1029  performAction:(FlutterTextInputAction)action
1030  withClient:(int)client {
1031  NSString* actionString;
1032  switch (action) {
1033  case FlutterTextInputActionUnspecified:
1034  // Where did the term "unspecified" come from? iOS has a "default" and Android
1035  // has "unspecified." These 2 terms seem to mean the same thing but we need
1036  // to pick just one. "unspecified" was chosen because "default" is often a
1037  // reserved word in languages with switch statements (dart, java, etc).
1038  actionString = @"TextInputAction.unspecified";
1039  break;
1040  case FlutterTextInputActionDone:
1041  actionString = @"TextInputAction.done";
1042  break;
1043  case FlutterTextInputActionGo:
1044  actionString = @"TextInputAction.go";
1045  break;
1046  case FlutterTextInputActionSend:
1047  actionString = @"TextInputAction.send";
1048  break;
1049  case FlutterTextInputActionSearch:
1050  actionString = @"TextInputAction.search";
1051  break;
1052  case FlutterTextInputActionNext:
1053  actionString = @"TextInputAction.next";
1054  break;
1055  case FlutterTextInputActionContinue:
1056  actionString = @"TextInputAction.continueAction";
1057  break;
1058  case FlutterTextInputActionJoin:
1059  actionString = @"TextInputAction.join";
1060  break;
1061  case FlutterTextInputActionRoute:
1062  actionString = @"TextInputAction.route";
1063  break;
1064  case FlutterTextInputActionEmergencyCall:
1065  actionString = @"TextInputAction.emergencyCall";
1066  break;
1067  case FlutterTextInputActionNewline:
1068  actionString = @"TextInputAction.newline";
1069  break;
1070  }
1071  [_textInputChannel.get() invokeMethod:@"TextInputClient.performAction"
1072  arguments:@[ @(client), actionString ]];
1073 }
1074 
1075 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1076  showAutocorrectionPromptRectForStart:(NSUInteger)start
1077  end:(NSUInteger)end
1078  withClient:(int)client {
1079  [_textInputChannel.get() invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
1080  arguments:@[ @(client), @(start), @(end) ]];
1081 }
1082 
1083 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1084  willDismissEditMenuWithTextInputClient:(int)client {
1085  [_platformChannel.get() invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
1086  arguments:@[ @(client) ]];
1087 }
1088 
1089 #pragma mark - FlutterViewEngineDelegate
1090 
1091 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView showToolbar:(int)client {
1092  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1093  // the framework has finished transitioning to the Scribble channel.
1094  // https://github.com/flutter/flutter/pull/115296
1095  [_textInputChannel.get() invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
1096 }
1097 
1098 - (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
1099  focusElement:(UIScribbleElementIdentifier)elementIdentifier
1100  atPoint:(CGPoint)referencePoint
1101  result:(FlutterResult)callback {
1102  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1103  // the framework has finished transitioning to the Scribble channel.
1104  // https://github.com/flutter/flutter/pull/115296
1105  [_textInputChannel.get()
1106  invokeMethod:@"TextInputClient.focusElement"
1107  arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
1108  result:callback];
1109 }
1110 
1111 - (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
1112  requestElementsInRect:(CGRect)rect
1113  result:(FlutterResult)callback {
1114  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1115  // the framework has finished transitioning to the Scribble channel.
1116  // https://github.com/flutter/flutter/pull/115296
1117  [_textInputChannel.get()
1118  invokeMethod:@"TextInputClient.requestElementsInRect"
1119  arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
1120  result:callback];
1121 }
1122 
1123 - (void)flutterTextInputViewScribbleInteractionBegan:(FlutterTextInputView*)textInputView {
1124  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1125  // the framework has finished transitioning to the Scribble channel.
1126  // https://github.com/flutter/flutter/pull/115296
1127  [_textInputChannel.get() invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
1128 }
1129 
1130 - (void)flutterTextInputViewScribbleInteractionFinished:(FlutterTextInputView*)textInputView {
1131  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1132  // the framework has finished transitioning to the Scribble channel.
1133  // https://github.com/flutter/flutter/pull/115296
1134  [_textInputChannel.get() invokeMethod:@"TextInputClient.scribbleInteractionFinished"
1135  arguments:nil];
1136 }
1137 
1138 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1139  insertTextPlaceholderWithSize:(CGSize)size
1140  withClient:(int)client {
1141  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1142  // the framework has finished transitioning to the Scribble channel.
1143  // https://github.com/flutter/flutter/pull/115296
1144  [_textInputChannel.get() invokeMethod:@"TextInputClient.insertTextPlaceholder"
1145  arguments:@[ @(client), @(size.width), @(size.height) ]];
1146 }
1147 
1148 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1149  removeTextPlaceholder:(int)client {
1150  // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1151  // the framework has finished transitioning to the Scribble channel.
1152  // https://github.com/flutter/flutter/pull/115296
1153  [_textInputChannel.get() invokeMethod:@"TextInputClient.removeTextPlaceholder"
1154  arguments:@[ @(client) ]];
1155 }
1156 
1157 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1158  didResignFirstResponderWithTextInputClient:(int)client {
1159  // When flutter text input view resign first responder, send a message to
1160  // framework to ensure the focus state is correct. This is useful when close
1161  // keyboard from platform side.
1162  [_textInputChannel.get() invokeMethod:@"TextInputClient.onConnectionClosed"
1163  arguments:@[ @(client) ]];
1164 
1165  // Platform view's first responder detection logic:
1166  //
1167  // All text input widgets (e.g. EditableText) are backed by a dummy UITextInput view
1168  // in the TextInputPlugin. When this dummy UITextInput view resigns first responder,
1169  // check if any platform view becomes first responder. If any platform view becomes
1170  // first responder, send a "viewFocused" channel message to inform the framework to un-focus
1171  // the previously focused text input.
1172  //
1173  // Caveat:
1174  // 1. This detection logic does not cover the scenario when a platform view becomes
1175  // first responder without any flutter text input resigning its first responder status
1176  // (e.g. user tapping on platform view first). For now it works fine because the TextInputPlugin
1177  // does not track the focused platform view id (which is different from Android implementation).
1178  //
1179  // 2. This detection logic assumes that all text input widgets are backed by a dummy
1180  // UITextInput view in the TextInputPlugin, which may not hold true in the future.
1181 
1182  // Have to check in the next run loop, because iOS requests the previous first responder to
1183  // resign before requesting the next view to become first responder.
1184  dispatch_async(dispatch_get_main_queue(), ^(void) {
1185  long platform_view_id = self.platformViewsController->FindFirstResponderPlatformViewId();
1186  if (platform_view_id == -1) {
1187  return;
1188  }
1189 
1190  [_platformViewsChannel.get() invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
1191  });
1192 }
1193 
1194 #pragma mark - Undo Manager Delegate
1195 
1196 - (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
1197  NSString* action = (direction == FlutterUndoRedoDirectionUndo) ? @"undo" : @"redo";
1198  [_undoManagerChannel.get() invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
1199 }
1200 
1201 - (UIView<UITextInput>*)activeTextInputView {
1202  return [[self textInputPlugin] textInputView];
1203 }
1204 
1205 - (NSUndoManager*)undoManager {
1206  return self.viewController.undoManager;
1207 }
1208 
1209 #pragma mark - Screenshot Delegate
1210 
1211 - (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
1212  asBase64Encoded:(BOOL)base64Encode {
1213  FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
1214  return _shell->Screenshot(type, base64Encode);
1215 }
1216 
1217 - (void)flutterViewAccessibilityDidCall {
1218  if (self.viewController.view.accessibilityElements == nil) {
1219  [self ensureSemanticsEnabled];
1220  }
1221 }
1222 
1223 - (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
1224  return _binaryMessenger;
1225 }
1226 
1227 - (NSObject<FlutterTextureRegistry>*)textureRegistry {
1228  return _textureRegistry;
1229 }
1230 
1231 // For test only. Ideally we should create a dependency injector for all dependencies and
1232 // remove this.
1233 - (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger {
1234  // Discard the previous messenger and keep the new one.
1235  if (binaryMessenger != _binaryMessenger) {
1236  _binaryMessenger.parent = nil;
1237  [_binaryMessenger release];
1238  _binaryMessenger = [binaryMessenger retain];
1239  }
1240 }
1241 
1242 #pragma mark - FlutterBinaryMessenger
1243 
1244 - (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
1245  [self sendOnChannel:channel message:message binaryReply:nil];
1246 }
1247 
1248 - (void)sendOnChannel:(NSString*)channel
1249  message:(NSData*)message
1250  binaryReply:(FlutterBinaryReply)callback {
1251  NSParameterAssert(channel);
1252  NSAssert(_shell && _shell->IsSetup(),
1253  @"Sending a message before the FlutterEngine has been run.");
1254  fml::RefPtr<flutter::PlatformMessageResponseDarwin> response =
1255  (callback == nil) ? nullptr
1256  : fml::MakeRefCounted<flutter::PlatformMessageResponseDarwin>(
1257  ^(NSData* reply) {
1258  callback(reply);
1259  },
1260  _shell->GetTaskRunners().GetPlatformTaskRunner());
1261  std::unique_ptr<flutter::PlatformMessage> platformMessage =
1262  (message == nil) ? std::make_unique<flutter::PlatformMessage>(channel.UTF8String, response)
1263  : std::make_unique<flutter::PlatformMessage>(
1264  channel.UTF8String, flutter::CopyNSDataToMapping(message), response);
1265 
1266  _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
1267  // platformMessage takes ownership of response.
1268  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1269 }
1270 
1271 - (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
1273 }
1274 
1275 - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
1276  binaryMessageHandler:
1277  (FlutterBinaryMessageHandler)handler {
1278  return [self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
1279 }
1280 
1282  setMessageHandlerOnChannel:(NSString*)channel
1283  binaryMessageHandler:(FlutterBinaryMessageHandler)handler
1284  taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
1285  NSParameterAssert(channel);
1286  if (_shell && _shell->IsSetup()) {
1287  self.iosPlatformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
1288  handler, taskQueue);
1289  return _connections->AquireConnection(channel.UTF8String);
1290  } else {
1291  NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
1292  // Setting a handler to nil for a channel that has not yet been set up is a no-op.
1294  }
1295 }
1296 
1297 - (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
1298  if (_shell && _shell->IsSetup()) {
1299  std::string channel = _connections->CleanupConnection(connection);
1300  if (!channel.empty()) {
1301  self.iosPlatformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.c_str(), nil,
1302  nil);
1303  }
1304  }
1305 }
1306 
1307 #pragma mark - FlutterTextureRegistry
1308 
1309 - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture {
1310  int64_t textureId = _nextTextureId++;
1311  self.iosPlatformView->RegisterExternalTexture(textureId, texture);
1312  return textureId;
1313 }
1314 
1315 - (void)unregisterTexture:(int64_t)textureId {
1316  _shell->GetPlatformView()->UnregisterTexture(textureId);
1317 }
1318 
1319 - (void)textureFrameAvailable:(int64_t)textureId {
1320  _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
1321 }
1322 
1323 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1324  return [FlutterDartProject lookupKeyForAsset:asset];
1325 }
1326 
1327 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1328  return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
1329 }
1330 
1331 - (id<FlutterPluginRegistry>)pluginRegistry {
1332  return self;
1333 }
1334 
1335 #pragma mark - FlutterPluginRegistry
1336 
1337 - (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
1338  NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
1339  self.pluginPublications[pluginKey] = [NSNull null];
1340  FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey
1341  flutterEngine:self];
1342  self.registrars[pluginKey] = result;
1343  return [result autorelease];
1344 }
1345 
1346 - (BOOL)hasPlugin:(NSString*)pluginKey {
1347  return _pluginPublications[pluginKey] != nil;
1348 }
1349 
1350 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1351  return _pluginPublications[pluginKey];
1352 }
1353 
1354 #pragma mark - Notifications
1355 
1356 #if APPLICATION_EXTENSION_API_ONLY
1357 - (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1358  [self flutterWillEnterForeground:notification];
1359 }
1360 
1361 - (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1362  [self flutterDidEnterBackground:notification];
1363 }
1364 #else
1365 - (void)applicationWillEnterForeground:(NSNotification*)notification {
1366  [self flutterWillEnterForeground:notification];
1367 }
1368 
1369 - (void)applicationDidEnterBackground:(NSNotification*)notification {
1370  [self flutterDidEnterBackground:notification];
1371 }
1372 #endif
1373 
1374 - (void)flutterWillEnterForeground:(NSNotification*)notification {
1375  [self setIsGpuDisabled:NO];
1376 }
1377 
1378 - (void)flutterDidEnterBackground:(NSNotification*)notification {
1379  [self setIsGpuDisabled:YES];
1380  [self notifyLowMemory];
1381 }
1382 
1383 - (void)onMemoryWarning:(NSNotification*)notification {
1384  [self notifyLowMemory];
1385 }
1386 
1387 - (void)setIsGpuDisabled:(BOOL)value {
1388  if (_shell) {
1389  _shell->SetGpuAvailability(value ? flutter::GpuAvailability::kUnavailable
1390  : flutter::GpuAvailability::kAvailable);
1391  }
1392  _isGpuDisabled = value;
1393 }
1394 
1395 #pragma mark - Locale updates
1396 
1397 - (void)onLocaleUpdated:(NSNotification*)notification {
1398  // Get and pass the user's preferred locale list to dart:ui.
1399  NSMutableArray<NSString*>* localeData = [[[NSMutableArray alloc] init] autorelease];
1400  NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
1401  for (NSString* localeID in preferredLocales) {
1402  NSLocale* locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease];
1403  NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
1404  NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
1405  NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
1406  NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
1407  if (!languageCode) {
1408  continue;
1409  }
1410  [localeData addObject:languageCode];
1411  [localeData addObject:(countryCode ? countryCode : @"")];
1412  [localeData addObject:(scriptCode ? scriptCode : @"")];
1413  [localeData addObject:(variantCode ? variantCode : @"")];
1414  }
1415  if (localeData.count == 0) {
1416  return;
1417  }
1418  [self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
1419 }
1420 
1421 - (void)waitForFirstFrame:(NSTimeInterval)timeout
1422  callback:(void (^_Nonnull)(BOOL didTimeout))callback {
1423  dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
1424  dispatch_async(queue, ^{
1425  fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
1426  BOOL didTimeout =
1427  self.shell.WaitForFirstFrame(waitTime).code() == fml::StatusCode::kDeadlineExceeded;
1428  dispatch_async(dispatch_get_main_queue(), ^{
1429  callback(didTimeout);
1430  });
1431  });
1432 }
1433 
1434 - (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
1435  libraryURI:(/*nullable*/ NSString*)libraryURI
1436  initialRoute:(/*nullable*/ NSString*)initialRoute
1437  entrypointArgs:(/*nullable*/ NSArray<NSString*>*)entrypointArgs {
1438  NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
1439  FlutterEngine* result = [[FlutterEngine alloc] initWithName:_labelPrefix
1440  project:_dartProject.get()
1441  allowHeadlessExecution:_allowHeadlessExecution];
1442  flutter::RunConfiguration configuration =
1443  [_dartProject.get() runConfigurationForEntrypoint:entrypoint
1444  libraryOrNil:libraryURI
1445  entrypointArgs:entrypointArgs];
1446 
1447  fml::WeakPtr<flutter::PlatformView> platform_view = _shell->GetPlatformView();
1448  FML_DCHECK(platform_view);
1449  // Static-cast safe since this class always creates PlatformViewIOS instances.
1450  flutter::PlatformViewIOS* ios_platform_view =
1451  static_cast<flutter::PlatformViewIOS*>(platform_view.get());
1452  std::shared_ptr<flutter::IOSContext> context = ios_platform_view->GetIosContext();
1453  FML_DCHECK(context);
1454 
1455  // Lambda captures by pointers to ObjC objects are fine here because the
1456  // create call is synchronous.
1457  flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
1458  [result, context](flutter::Shell& shell) {
1459  [result recreatePlatformViewController];
1460  return std::make_unique<flutter::PlatformViewIOS>(
1461  shell, context, result->_platformViewsController, shell.GetTaskRunners());
1462  };
1463 
1464  flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
1465  [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
1466 
1467  std::string cppInitialRoute;
1468  if (initialRoute) {
1469  cppInitialRoute = [initialRoute UTF8String];
1470  }
1471 
1472  std::unique_ptr<flutter::Shell> shell = _shell->Spawn(
1473  std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1474 
1475  result->_threadHost = _threadHost;
1476  result->_profiler = _profiler;
1477  result->_profiler_metrics = _profiler_metrics;
1478  result->_isGpuDisabled = _isGpuDisabled;
1479  [result setUpShell:std::move(shell) withVMServicePublication:NO];
1480  return [result autorelease];
1481 }
1482 
1483 - (const flutter::ThreadHost&)threadHost {
1484  return *_threadHost;
1485 }
1486 
1487 - (FlutterDartProject*)project {
1488  return _dartProject.get();
1489 }
1490 
1491 - (BOOL)isUsingImpeller {
1492  return self.project.isImpellerEnabled;
1493 }
1494 
1495 @end
1496 
1497 @implementation FlutterEngineRegistrar {
1498  NSString* _pluginKey;
1499 }
1500 
1501 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
1502  self = [super init];
1503  NSAssert(self, @"Super init cannot be nil");
1504  _pluginKey = [pluginKey copy];
1505  _flutterEngine = flutterEngine;
1506  return self;
1507 }
1508 
1509 - (void)dealloc {
1510  [_pluginKey release];
1511  [super dealloc];
1512 }
1513 
1514 - (NSObject<FlutterBinaryMessenger>*)messenger {
1515  return _flutterEngine.binaryMessenger;
1516 }
1517 
1518 - (NSObject<FlutterTextureRegistry>*)textures {
1519  return _flutterEngine.textureRegistry;
1520 }
1521 
1522 - (void)publish:(NSObject*)value {
1523  _flutterEngine.pluginPublications[_pluginKey] = value;
1524 }
1525 
1526 - (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
1527  channel:(FlutterMethodChannel*)channel {
1528  [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1529  [delegate handleMethodCall:call result:result];
1530  }];
1531 }
1532 
1533 - (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate
1534  NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in plugins used in app extensions") {
1535  id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
1536  if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifeCycleProvider)]) {
1537  id<FlutterAppLifeCycleProvider> lifeCycleProvider =
1538  (id<FlutterAppLifeCycleProvider>)appDelegate;
1539  [lifeCycleProvider addApplicationLifeCycleDelegate:delegate];
1540  }
1541 }
1542 
1543 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1544  return [_flutterEngine lookupKeyForAsset:asset];
1545 }
1546 
1547 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1548  return [_flutterEngine lookupKeyForAsset:asset fromPackage:package];
1549 }
1550 
1551 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1552  withId:(NSString*)factoryId {
1553  [self registerViewFactory:factory
1554  withId:factoryId
1555  gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
1556 }
1557 
1558 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1559  withId:(NSString*)factoryId
1560  gestureRecognizersBlockingPolicy:
1561  (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy {
1562  [_flutterEngine platformViewsController]->RegisterViewFactory(factory, factoryId,
1563  gestureRecognizersBlockingPolicy);
1564 }
1565 
1566 @end
_restorationChannel
fml::scoped_nsobject< FlutterMethodChannel > _restorationChannel
Definition: FlutterEngine.mm:138
FlutterTextureRegistryRelay::parent
NSObject< FlutterTextureRegistry > * parent
Definition: FlutterTextureRegistryRelay.h:25
_weakFactory
std::unique_ptr< fml::WeakNSObjectFactory< FlutterEngine > > _weakFactory
Definition: FlutterEngine.mm:120
self
return self
Definition: FlutterTextureRegistryRelay.mm:19
flutter::PlatformMessageHandlerIos::MakeBackgroundTaskQueue
static NSObject< FlutterTaskQueue > * MakeBackgroundTaskQueue()
Definition: platform_message_handler_ios.mm:36
FlutterDartProject::isImpellerEnabled
BOOL isImpellerEnabled
Definition: FlutterDartProject_Internal.h:22
FlutterEngine
Definition: FlutterEngine.h:61
FlutterView::forceSoftwareRendering
BOOL forceSoftwareRendering
Definition: FlutterView.h:49
FlutterPlugin-p
Definition: FlutterPlugin.h:189
_undoManagerChannel
fml::scoped_nsobject< FlutterMethodChannel > _undoManagerChannel
Definition: FlutterEngine.mm:142
FlutterTextInputDelegate-p
Definition: FlutterTextInputDelegate.h:37
_viewController
fml::WeakNSObject< FlutterViewController > _viewController
Definition: FlutterEngine.mm:122
FlutterDefaultInitialRoute
NSString *const FlutterDefaultInitialRoute
Definition: FlutterEngine.mm:81
FlutterTextInputPlugin::indirectScribbleDelegate
id< FlutterIndirectScribbleDelegate > indirectScribbleDelegate
Definition: FlutterTextInputPlugin.h:37
FlutterSpellCheckPlugin
Definition: FlutterSpellCheckPlugin.h:11
FlutterDefaultDartEntrypoint
NSString *const FlutterDefaultDartEntrypoint
Definition: FlutterEngine.mm:80
_labelPrefix
NSString * _labelPrefix
Definition: FlutterEngine.mm:119
FlutterBasicMessageChannel
Definition: FlutterChannels.h:37
flutter::ConnectionCollection
Maintains a current integer assigned to a name (connections).
Definition: connection_collection.h:15
FlutterViewController
Definition: FlutterViewController.h:56
FlutterMethodChannel
Definition: FlutterChannels.h:220
FlutterEngineRegistrar::flutterEngine
FlutterEngine * flutterEngine
Definition: FlutterEngine.mm:90
FlutterEngine(Test)::embedderAPI
FlutterEngineProcTable & embedderAPI
Definition: FlutterEngine_Test.h:25
FlutterEngine::isolateId
NSString * isolateId
Definition: FlutterEngine.h:449
_lifecycleChannel
fml::scoped_nsobject< FlutterBasicMessageChannel > _lifecycleChannel
Definition: FlutterEngine.mm:145
_textInputPlugin
fml::scoped_nsobject< FlutterTextInputPlugin > _textInputPlugin
Definition: FlutterEngine.mm:132
FlutterTextInputDelegate.h
FlutterUndoManagerPlugin.h
-[FlutterEngine initWithName:project:allowHeadlessExecution:]
instancetype initWithName:project:allowHeadlessExecution:(NSString *labelPrefix,[project] nullable FlutterDartProject *project,[allowHeadlessExecution] BOOL allowHeadlessExecution)
FlutterRestorationPlugin
Definition: FlutterRestorationPlugin.h:12
FlutterTextureRegistry-p
Definition: FlutterTexture.h:45
_navigationChannel
fml::scoped_nsobject< FlutterMethodChannel > _navigationChannel
Definition: FlutterEngine.mm:137
connection_collection.h
_textInputChannel
fml::scoped_nsobject< FlutterMethodChannel > _textInputChannel
Definition: FlutterEngine.mm:141
FlutterEngine_Internal.h
command_line.h
+[FlutterDartProject lookupKeyForAsset:]
NSString * lookupKeyForAsset:(NSString *asset)
Definition: FlutterDartProject.mm:388
FlutterError
Definition: FlutterCodecs.h:246
kNumProfilerSamplesPerSec
static constexpr int kNumProfilerSamplesPerSec
Definition: FlutterEngine.mm:87
FlutterDartVMServicePublisher.h
-[FlutterPlatformPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterPlatformPlugin.mm:103
-[FlutterEngine runWithEntrypoint:libraryURI:initialRoute:]
BOOL runWithEntrypoint:libraryURI:initialRoute:(nullable NSString *entrypoint,[libraryURI] nullable NSString *libraryURI,[initialRoute] nullable NSString *initialRoute)
_profiler_metrics
std::shared_ptr< flutter::ProfilerMetricsIOS > _profiler_metrics
Definition: FlutterEngine.mm:127
flutter::CopyNSDataToMapping
fml::MallocMapping CopyNSDataToMapping(NSData *data)
Definition: buffer_conversions.mm:30
_settingsChannel
fml::scoped_nsobject< FlutterBasicMessageChannel > _settingsChannel
Definition: FlutterEngine.mm:147
platform_view
std::unique_ptr< flutter::PlatformViewIOS > platform_view
Definition: FlutterEnginePlatformViewTest.mm:65
+[FlutterError errorWithCode:message:details:]
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
_connections
std::unique_ptr< flutter::ConnectionCollection > _connections
Definition: FlutterEngine.mm:157
FlutterPluginRegistrar-p
Definition: FlutterPlugin.h:283
-[FlutterTextInputPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterTextInputPlugin.mm:2389
flutter::PlatformViewIOS
Definition: platform_view_ios.h:41
flutter::PlatformViewIOS::GetIosContext
const std::shared_ptr< IOSContext > & GetIosContext()
Definition: platform_view_ios.h:93
_publisher
fml::scoped_nsobject< FlutterDartVMServicePublisher > _publisher
Definition: FlutterEngine.mm:123
_spellCheckChannel
fml::scoped_nsobject< FlutterMethodChannel > _spellCheckChannel
Definition: FlutterEngine.mm:144
FlutterIndirectScribbleDelegate-p
Definition: FlutterIndirectScribbleDelegate.h:13
-[FlutterTextInputPlugin setUpIndirectScribbleInteraction:]
void setUpIndirectScribbleInteraction:(id< FlutterViewResponder > viewResponder)
Definition: FlutterTextInputPlugin.mm:3022
viewController
FlutterViewController * viewController
Definition: FlutterTextInputPluginTest.mm:92
FlutterBinaryMessageHandler
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
Definition: FlutterBinaryMessenger.h:30
_platformViewsController
std::shared_ptr< flutter::FlutterPlatformViewsController > _platformViewsController
Definition: FlutterEngine.mm:125
-[FlutterUndoManagerPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterUndoManagerPlugin.mm:38
FlutterTextInputView
Definition: FlutterTextInputPlugin.mm:802
-[FlutterMethodChannel setMethodCallHandler:]
void setMethodCallHandler:(FlutterMethodCallHandler _Nullable handler)
FlutterBinaryMessengerRelay.h
kFlutterKeyDataChannel
NSString *const kFlutterKeyDataChannel
Definition: FlutterEngine.mm:86
profiler_metrics_ios.h
flutter::ConnectionCollection::MakeErrorConnection
static Connection MakeErrorConnection(int errCode)
Definition: connection_collection.mm:39
flutter::GetRenderingAPIForProcess
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
Definition: rendering_api_selection.mm:31
FlutterStringCodec
Definition: FlutterCodecs.h:63
_spellCheckPlugin
fml::scoped_nsobject< FlutterSpellCheckPlugin > _spellCheckPlugin
Definition: FlutterEngine.mm:134
_undoManagerPlugin
fml::scoped_nsobject< FlutterUndoManagerPlugin > _undoManagerPlugin
Definition: FlutterEngine.mm:133
FlutterSpellCheckPlugin.h
flutter
Definition: accessibility_bridge.h:28
_scribbleChannel
fml::scoped_nsobject< FlutterMethodChannel > _scribbleChannel
Definition: FlutterEngine.mm:143
_textureRegistry
FlutterTextureRegistryRelay * _textureRegistry
Definition: FlutterEngine.mm:156
IOSPlatformThreadConfigSetter
static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig &config)
Definition: FlutterEngine.mm:46
FlutterTextInputPlugin
Definition: FlutterTextInputPlugin.h:33
_systemChannel
fml::scoped_nsobject< FlutterBasicMessageChannel > _systemChannel
Definition: FlutterEngine.mm:146
_profiler
std::shared_ptr< flutter::SamplingProfiler > _profiler
Definition: FlutterEngine.mm:128
flutter::IOSRenderingAPI
IOSRenderingAPI
Definition: rendering_api_selection.h:14
FlutterTextureRegistryRelay
Definition: FlutterTextureRegistryRelay.h:20
FlutterTaskQueue-p
Definition: FlutterBinaryMessenger.h:34
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
UIViewController+FlutterScreenAndSceneIfLoaded.h
FlutterPlatformViewGestureRecognizersBlockingPolicy
FlutterPlatformViewGestureRecognizersBlockingPolicy
Definition: FlutterPlugin.h:252
_keyEventChannel
fml::scoped_nsobject< FlutterBasicMessageChannel > _keyEventChannel
Definition: FlutterEngine.mm:148
FlutterIndirectScribbleDelegate.h
FlutterPlatformPlugin.h
_renderingApi
flutter::IOSRenderingAPI _renderingApi
Definition: FlutterEngine.mm:126
FlutterTexture
Definition: FlutterMetalLayer.mm:58
-[FlutterPlugin-p handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
_binaryMessenger
FlutterBinaryMessengerRelay * _binaryMessenger
Definition: FlutterEngine.mm:155
rendering_api_selection.h
FlutterAppLifeCycleProvider-p
Definition: FlutterPlugin.h:436
FlutterPlatformViewFactory-p
Definition: FlutterPlatformViews.h:26
_screenshotChannel
fml::scoped_nsobject< FlutterMethodChannel > _screenshotChannel
Definition: FlutterEngine.mm:149
_shell
std::unique_ptr< flutter::Shell > _shell
Definition: FlutterEngine.mm:118
FlutterUndoManagerDelegate-p
Definition: FlutterUndoManagerDelegate.h:23
FlutterDartProject_Internal.h
textInputPlugin
FlutterTextInputPlugin * textInputPlugin
Definition: FlutterTextInputPluginTest.mm:90
FlutterViewController_Internal.h
FlutterUndoManagerPlugin
Definition: FlutterUndoManagerPlugin.h:13
FlutterPlatformPlugin
Definition: FlutterPlatformPlugin.h:12
_restorationEnabled
BOOL _restorationEnabled
Definition: FlutterEngine.mm:154
FlutterView
Definition: FlutterView.h:34
_platformChannel
fml::scoped_nsobject< FlutterMethodChannel > _platformChannel
Definition: FlutterEngine.mm:139
FlutterBinaryMessengerRelay
Definition: FlutterBinaryMessengerRelay.h:14
FlutterJSONMethodCodec
Definition: FlutterCodecs.h:455
vsync_waiter_ios.h
+[FlutterDartProject lookupKeyForAsset:fromPackage:]
NSString * lookupKeyForAsset:fromPackage:(NSString *asset,[fromPackage] NSString *package)
Definition: FlutterDartProject.mm:397
FlutterEngineRegistrar
Definition: FlutterEngine.mm:89
platform_view_ios.h
_nextTextureId
int64_t _nextTextureId
Definition: FlutterEngine.mm:151
FlutterEngine(Test)::enableEmbedderAPI
BOOL enableEmbedderAPI
Definition: FlutterEngine_Test.h:26
FlutterDartProject
Definition: FlutterDartProject.mm:262
FlutterTextureRegistryRelay.h
_localizationChannel
fml::scoped_nsobject< FlutterMethodChannel > _localizationChannel
Definition: FlutterEngine.mm:136
_allowHeadlessExecution
BOOL _allowHeadlessExecution
Definition: FlutterEngine.mm:153
FlutterBinaryMessenger-p
Definition: FlutterBinaryMessenger.h:49
FlutterBinaryMessengerRelay::parent
NSObject< FlutterBinaryMessenger > * parent
Definition: FlutterBinaryMessengerRelay.h:15
FlutterDartVMServicePublisher
Definition: FlutterDartVMServicePublisher.h:10
platform_message_response_darwin.h
_threadHost
std::shared_ptr< flutter::ThreadHost > _threadHost
Definition: FlutterEngine.mm:115
FlutterUndoManagerDelegate.h
FlutterStandardMethodCodec
Definition: FlutterCodecs.h:469
kFlutterEngineWillDealloc
NSString *const kFlutterEngineWillDealloc
Definition: FlutterEngine.mm:85
FlutterBinaryMessengerConnection
int64_t FlutterBinaryMessengerConnection
Definition: FlutterBinaryMessenger.h:32
_restorationPlugin
fml::scoped_nsobject< FlutterRestorationPlugin > _restorationPlugin
Definition: FlutterEngine.mm:135
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
_platformViewsChannel
fml::scoped_nsobject< FlutterMethodChannel > _platformViewsChannel
Definition: FlutterEngine.mm:140
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()
flutter::FlutterPlatformViewsController
Definition: FlutterPlatformViews_Internal.h:205
_platformPlugin
fml::scoped_nsobject< FlutterPlatformPlugin > _platformPlugin
Definition: FlutterEngine.mm:131
-[FlutterSpellCheckPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterSpellCheckPlugin.mm:38
FlutterJSONMessageCodec
Definition: FlutterCodecs.h:81