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