| 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 #include "common/settings.h"
6 #define FML_USED_ON_EMBEDDER
7
8 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h"
9
10 #include <memory>
11
12 #include "flutter/common/constants.h"
13 #include "flutter/fml/message_loop.h"
14 #include "flutter/fml/platform/darwin/platform_version.h"
15 #include "flutter/fml/platform/darwin/weak_nsobject.h"
16 #include "flutter/fml/trace_event.h"
17 #include "flutter/runtime/ptrace_check.h"
18 #include "flutter/shell/common/engine.h"
19 #include "flutter/shell/common/platform_view.h"
20 #include "flutter/shell/common/shell.h"
21 #include "flutter/shell/common/switches.h"
22 #include "flutter/shell/common/thread_host.h"
23 #include "flutter/shell/common/variable_refresh_rate_display.h"
24 #import "flutter/shell/platform/darwin/common/command_line.h"
25 #import "flutter/shell/platform/darwin/common/framework/Source/FlutterBinaryMessengerRelay.h"
26 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
27 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartVMServicePublisher.h"
28 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterIndirectScribbleDelegate.h"
29 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h"
30 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSpellCheckPlugin.h"
31 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h"
32 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h"
33 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUndoManagerDelegate.h"
34 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUndoManagerPlugin.h"
35 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
36 #import "flutter/shell/platform/darwin/ios/framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.h"
37 #import "flutter/shell/platform/darwin/ios/framework/Source/connection_collection.h"
38 #import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
39 #import "flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h"
40 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
41 #import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
42 #import "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
43 #include "flutter/shell/profiling/sampling_profiler.h"
44
45 /// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities
46 /// Using iOS platform thread API to configure thread priority
47 static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig& config) {
48 // set thread name
49 fml::Thread::SetCurrentThreadName(config);
50
51 // set thread priority
52 switch (config.priority) {
53 case fml::Thread::ThreadPriority::kBackground: {
54 pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
55 [[NSThread currentThread] setThreadPriority:0];
56 break;
57 }
58 case fml::Thread::ThreadPriority::kNormal: {
59 pthread_set_qos_class_self_np(QOS_CLASS_DEFAULT, 0);
60 [[NSThread currentThread] setThreadPriority:0.5];
61 break;
62 }
63 case fml::Thread::ThreadPriority::kRaster:
64 case fml::Thread::ThreadPriority::kDisplay: {
65 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
66 [[NSThread currentThread] setThreadPriority:1.0];
67 sched_param param;
68 int policy;
69 pthread_t thread = pthread_self();
70 if (!pthread_getschedparam(thread, &policy, &param)) {
71 param.sched_priority = 50;
72 pthread_setschedparam(thread, policy, &param);
73 }
74 break;
75 }
76 }
77 }
78
79 #pragma mark - Public exported constants
80
81 NSString* const FlutterDefaultDartEntrypoint = nil;
82 NSString* const FlutterDefaultInitialRoute = nil;
83
84 #pragma mark - Internal constants
85
86 NSString* const kFlutterEngineWillDealloc = @"FlutterEngineWillDealloc";
87 NSString* const kFlutterKeyDataChannel = @"flutter/keydata";
88 static constexpr int kNumProfilerSamplesPerSec = 5;
89
90 @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
91 @property(nonatomic, assign) FlutterEngine* flutterEngine;
92 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
93 @end
94
95 @interface FlutterEngine () <FlutterIndirectScribbleDelegate,
96 FlutterUndoManagerDelegate,
97 FlutterTextInputDelegate,
98 FlutterBinaryMessenger,
99 FlutterTextureRegistry>
100 // Maintains a dictionary of plugin names that have registered with the engine. Used by
101 // FlutterEngineRegistrar to implement a FlutterPluginRegistrar.
102 @property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
103 @property(nonatomic, readonly) NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* registrars;
104
105 @property(nonatomic, readwrite, copy) NSString* isolateId;
106 @property(nonatomic, copy) NSString* initialRoute;
107 @property(nonatomic, retain) id<NSObject> flutterViewControllerWillDeallocObserver;
108
109 #pragma mark - Embedder API properties
110
111 @property(nonatomic, assign) BOOL enableEmbedderAPI;
112 // Function pointers for interacting with the embedder.h API.
113 @property(nonatomic) FlutterEngineProcTable& embedderAPI;
114 @end
115
116 @implementation FlutterEngine {
117 fml::scoped_nsobject<FlutterDartProject> _dartProject;
118 std::shared_ptr<flutter::ThreadHost> _threadHost;
119 std::unique_ptr<flutter::Shell> _shell;
120 NSString* _labelPrefix;
121 std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory;
122
123 fml::WeakNSObject<FlutterViewController> _viewController;
124 fml::scoped_nsobject<FlutterDartVMServicePublisher> _publisher;
125
126 std::shared_ptr<flutter::PlatformViewsController> _platformViewsController;
127 flutter::IOSRenderingAPI _renderingApi;
128 std::shared_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
129 std::shared_ptr<flutter::SamplingProfiler> _profiler;
130
131 // Channels
132 fml::scoped_nsobject<FlutterPlatformPlugin> _platformPlugin;
133 fml::scoped_nsobject<FlutterTextInputPlugin> _textInputPlugin;
134 fml::scoped_nsobject<FlutterUndoManagerPlugin> _undoManagerPlugin;
135 fml::scoped_nsobject<FlutterSpellCheckPlugin> _spellCheckPlugin;
136 fml::scoped_nsobject<FlutterRestorationPlugin> _restorationPlugin;
137 fml::scoped_nsobject<FlutterMethodChannel> _localizationChannel;
138 fml::scoped_nsobject<FlutterMethodChannel> _navigationChannel;
139 fml::scoped_nsobject<FlutterMethodChannel> _restorationChannel;
140 fml::scoped_nsobject<FlutterMethodChannel> _platformChannel;
141 fml::scoped_nsobject<FlutterMethodChannel> _platformViewsChannel;
142 fml::scoped_nsobject<FlutterMethodChannel> _textInputChannel;
143 fml::scoped_nsobject<FlutterMethodChannel> _undoManagerChannel;
144 fml::scoped_nsobject<FlutterMethodChannel> _scribbleChannel;
145 fml::scoped_nsobject<FlutterMethodChannel> _spellCheckChannel;
146 fml::scoped_nsobject<FlutterBasicMessageChannel> _lifecycleChannel;
147 fml::scoped_nsobject<FlutterBasicMessageChannel> _systemChannel;
148 fml::scoped_nsobject<FlutterBasicMessageChannel> _settingsChannel;
149 fml::scoped_nsobject<FlutterBasicMessageChannel> _keyEventChannel;
150 fml::scoped_nsobject<FlutterMethodChannel> _screenshotChannel;
151
152 int64_t _nextTextureId;
153
154 BOOL _allowHeadlessExecution;
155 BOOL _restorationEnabled;
156 FlutterBinaryMessengerRelay* _binaryMessenger;
157 FlutterTextureRegistryRelay* _textureRegistry;
158 std::unique_ptr<flutter::ConnectionCollection> _connections;
159 }
160
161 - (instancetype)init {
162 return [self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
163 }
164
165 - (instancetype)initWithName:(NSString*)labelPrefix {
166 return [self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
167 }
168
169 - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
170 return [self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
171 }
172
173 - (instancetype)initWithName:(NSString*)labelPrefix
174 project:(FlutterDartProject*)project
175 allowHeadlessExecution:(BOOL)allowHeadlessExecution {
176 return [self initWithName:labelPrefix
177 project:project
178 allowHeadlessExecution:allowHeadlessExecution
179 restorationEnabled:NO];
180 }
181
182 - (instancetype)initWithName:(NSString*)labelPrefix
183 project:(FlutterDartProject*)project
184 allowHeadlessExecution:(BOOL)allowHeadlessExecution
185 restorationEnabled:(BOOL)restorationEnabled {
186 self = [super init];
187 NSAssert(self, @"Super init cannot be nil");
188 NSAssert(labelPrefix, @"labelPrefix is required");
189
190 _restorationEnabled = restorationEnabled;
191 _allowHeadlessExecution = allowHeadlessExecution;
192 _labelPrefix = [labelPrefix copy];
193
194 _weakFactory = std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(self);
195
196 if (project == nil) {
197 _dartProject.reset([[FlutterDartProject alloc] init]);
198 } else {
199 _dartProject.reset([project retain]);
200 }
201
202 _enableEmbedderAPI = _dartProject.get().settings.enable_embedder_api;
203 if (_enableEmbedderAPI) {
204 NSLog(@"============== iOS: enable_embedder_api is on ==============");
205 _embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
206 FlutterEngineGetProcAddresses(&_embedderAPI);
207 }
208
209 if (!EnableTracingIfNecessary([_dartProject.get() settings])) {
210 NSLog(
211 @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
212 @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
213 @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
214 @"profile and release mode apps can be launched from the home screen.");
215 [self release];
216 return nil;
217 }
218
219 _pluginPublications = [[NSMutableDictionary alloc] init];
220 _registrars = [[NSMutableDictionary alloc] init];
221 [self recreatePlatformViewController];
222 _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
223 _textureRegistry = [[FlutterTextureRegistryRelay alloc] initWithParent:self];
224 _connections.reset(new flutter::ConnectionCollection());
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 {
273 _renderingApi = flutter::GetRenderingAPIForProcess(FlutterView.forceSoftwareRendering);
274 _platformViewsController.reset(new flutter::PlatformViewsController());
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;
467 if (!_allowHeadlessExecution) {
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
488 - (FlutterViewController*)viewController {
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::PlatformViewsController>&)platformViewsController {
499 return _platformViewsController;
500 }
501 - (FlutterTextInputPlugin*)textInputPlugin {
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
595 _localizationChannel.reset([[FlutterMethodChannel alloc]
596 initWithName:@"flutter/localization"
597 binaryMessenger:self.binaryMessenger
598 codec:[FlutterJSONMethodCodec sharedInstance]]);
599
600 _navigationChannel.reset([[FlutterMethodChannel alloc]
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
612 _restorationChannel.reset([[FlutterMethodChannel alloc]
613 initWithName:@"flutter/restoration"
614 binaryMessenger:self.binaryMessenger
615 codec:[FlutterStandardMethodCodec sharedInstance]]);
616
617 _platformChannel.reset([[FlutterMethodChannel alloc]
618 initWithName:@"flutter/platform"
619 binaryMessenger:self.binaryMessenger
620 codec:[FlutterJSONMethodCodec sharedInstance]]);
621
622 _platformViewsChannel.reset([[FlutterMethodChannel alloc]
623 initWithName:@"flutter/platform_views"
624 binaryMessenger:self.binaryMessenger
625 codec:[FlutterStandardMethodCodec sharedInstance]]);
626
627 _textInputChannel.reset([[FlutterMethodChannel alloc]
628 initWithName:@"flutter/textinput"
629 binaryMessenger:self.binaryMessenger
630 codec:[FlutterJSONMethodCodec sharedInstance]]);
631
632 _undoManagerChannel.reset([[FlutterMethodChannel alloc]
633 initWithName:@"flutter/undomanager"
634 binaryMessenger:self.binaryMessenger
635 codec:[FlutterJSONMethodCodec sharedInstance]]);
636
637 _scribbleChannel.reset([[FlutterMethodChannel alloc]
638 initWithName:@"flutter/scribble"
639 binaryMessenger:self.binaryMessenger
640 codec:[FlutterJSONMethodCodec sharedInstance]]);
641
642 _spellCheckChannel.reset([[FlutterMethodChannel alloc]
643 initWithName:@"flutter/spellcheck"
644 binaryMessenger:self.binaryMessenger
645 codec:[FlutterStandardMethodCodec sharedInstance]]);
646
647 _lifecycleChannel.reset([[FlutterBasicMessageChannel alloc]
648 initWithName:@"flutter/lifecycle"
649 binaryMessenger:self.binaryMessenger
650 codec:[FlutterStringCodec sharedInstance]]);
651
652 _systemChannel.reset([[FlutterBasicMessageChannel alloc]
653 initWithName:@"flutter/system"
654 binaryMessenger:self.binaryMessenger
655 codec:[FlutterJSONMessageCodec sharedInstance]]);
656
657 _settingsChannel.reset([[FlutterBasicMessageChannel alloc]
658 initWithName:@"flutter/settings"
659 binaryMessenger:self.binaryMessenger
660 codec:[FlutterJSONMessageCodec sharedInstance]]);
661
662 _keyEventChannel.reset([[FlutterBasicMessageChannel alloc]
663 initWithName:@"flutter/keyevent"
664 binaryMessenger:self.binaryMessenger
665 codec:[FlutterJSONMessageCodec sharedInstance]]);
666
667 FlutterTextInputPlugin* textInputPlugin = [[FlutterTextInputPlugin alloc] initWithDelegate:self];
668 _textInputPlugin.reset(textInputPlugin);
669 textInputPlugin.indirectScribbleDelegate = 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
678 _restorationPlugin.reset([[FlutterRestorationPlugin alloc]
679 initWithChannel:_restorationChannel.get()
680 restorationEnabled:_restorationEnabled]);
681 _spellCheckPlugin.reset([[FlutterSpellCheckPlugin alloc] init]);
682
683 _screenshotChannel.reset([[FlutterMethodChannel alloc]
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
729 FlutterTextInputPlugin* textInputPlugin = _textInputPlugin.get();
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];
768 _publisher.reset([[FlutterDartVMServicePublisher alloc]
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 static flutter::ThreadHost MakeThreadHost(NSString* thread_label,
790 const flutter::Settings& settings) {
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::kRaster | flutter::ThreadHost::Type::kIo |
796 flutter::ThreadHost::Type::kUi;
797
798 if ([FlutterEngine isProfilerEnabled]) {
799 threadHostType = threadHostType | flutter::ThreadHost::Type::kProfiler;
800 }
801
802 flutter::ThreadHost::ThreadHostConfig host_config(thread_label.UTF8String, threadHostType,
803 IOSPlatformThreadConfigSetter);
804
805 host_config.ui_config =
806 fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
807 flutter::ThreadHost::Type::kUi, thread_label.UTF8String),
808 fml::Thread::ThreadPriority::kDisplay);
809 host_config.raster_config =
810 fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
811 flutter::ThreadHost::Type::kRaster, thread_label.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, thread_label.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 = MakeThreadHost(threadLabel, settings);
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 self->_platformViewsController->SetTaskRunner(
869 shell.GetTaskRunners().GetPlatformTaskRunner());
870 return std::make_unique<flutter::PlatformViewIOS>(
871 shell, self->_renderingApi, self->_platformViewsController, shell.GetTaskRunners(),
872 shell.GetConcurrentWorkerTaskRunner(), shell.GetIsGpuDisabledSyncSwitch());
873 };
874
875 flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
876 [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
877
878 fml::RefPtr<fml::TaskRunner> ui_runner = _threadHost->ui_thread->GetTaskRunner();
879 flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
880 fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
881 _threadHost->raster_thread->GetTaskRunner(), // raster
882 ui_runner, // ui
883 _threadHost->io_thread->GetTaskRunner() // io
884 );
885
886 #if APPLICATION_EXTENSION_API_ONLY
887 if (@available(iOS 13.0, *)) {
888 _isGpuDisabled = self.viewController.flutterWindowSceneIfViewLoaded.activationState ==
889 UISceneActivationStateBackground;
890 } else {
891 // [UIApplication sharedApplication API is not available for app extension.
892 // We intialize the shell assuming the GPU is required.
893 _isGpuDisabled = NO;
894 }
895 #else
896 _isGpuDisabled =
897 [UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
898 #endif
899
900 // Create the shell. This is a blocking operation.
901 std::unique_ptr<flutter::Shell> shell = flutter::Shell::Create(
902 /*platform_data=*/platformData,
903 /*task_runners=*/task_runners,
904 /*settings=*/settings,
905 /*on_create_platform_view=*/on_create_platform_view,
906 /*on_create_rasterizer=*/on_create_rasterizer,
907 /*is_gpu_disabled=*/_isGpuDisabled);
908
909 if (shell == nullptr) {
910 FML_LOG(ERROR) << "Could not start a shell FlutterEngine with entrypoint: "
911 << entrypoint.UTF8String;
912 } else {
913 // TODO(vashworth): Remove once done debugging https://github.com/flutter/flutter/issues/129836
914 FML_LOG(INFO) << "Enabled VM Service Publication: " << settings.enable_vm_service_publication;
915 [self setUpShell:std::move(shell)
916 withVMServicePublication:settings.enable_vm_service_publication];
917 if ([FlutterEngine isProfilerEnabled]) {
918 [self startProfiler];
919 }
920 }
921
922 return _shell != nullptr;
923 }
924
925 - (void)updateDisplays {
926 if (!_shell) {
927 // Tests may do this.
928 return;
929 }
930 auto vsync_waiter = _shell->GetVsyncWaiter().lock();
931 auto vsync_waiter_ios = std::static_pointer_cast<flutter::VsyncWaiterIOS>(vsync_waiter);
932 std::vector<std::unique_ptr<flutter::Display>> displays;
933 auto screen_size = UIScreen.mainScreen.nativeBounds.size;
934 auto scale = UIScreen.mainScreen.scale;
935 displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(
936 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale));
937 _shell->OnDisplayUpdates(std::move(displays));
938 }
939
940 - (BOOL)run {
941 return [self runWithEntrypoint:FlutterDefaultDartEntrypoint
942 libraryURI:nil
943 initialRoute:FlutterDefaultInitialRoute];
944 }
945
946 - (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
947 return [self runWithEntrypoint:entrypoint
948 libraryURI:libraryURI
949 initialRoute:FlutterDefaultInitialRoute];
950 }
951
952 - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
953 return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
954 }
955
956 - (BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
957 return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
958 }
959
960 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
961 libraryURI:(NSString*)libraryURI
962 initialRoute:(NSString*)initialRoute {
963 return [self runWithEntrypoint:entrypoint
964 libraryURI:libraryURI
965 initialRoute:initialRoute
966 entrypointArgs:nil];
967 }
968
969 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
970 libraryURI:(NSString*)libraryURI
971 initialRoute:(NSString*)initialRoute
972 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
973 if ([self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
974 [self launchEngine:entrypoint libraryURI:libraryURI entrypointArgs:entrypointArgs];
975 }
976
977 return _shell != nullptr;
978 }
979
980 - (void)notifyLowMemory {
981 if (_shell) {
982 _shell->NotifyLowMemoryWarning();
983 }
984 [_systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
985 }
986
987 #pragma mark - Text input delegate
988
989 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
990 updateEditingClient:(int)client
991 withState:(NSDictionary*)state {
992 [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingState"
993 arguments:@[ @(client), state ]];
994 }
995
996 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
997 updateEditingClient:(int)client
998 withState:(NSDictionary*)state
999 withTag:(NSString*)tag {
1000 [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithTag"
1001 arguments:@[ @(client), @{tag : state} ]];
1002 }
1003
1004 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1005 updateEditingClient:(int)client
1006 withDelta:(NSDictionary*)delta {
1007 [_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
1008 arguments:@[ @(client), delta ]];
1009 }
1010
1011 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1012 updateFloatingCursor:(FlutterFloatingCursorDragState)state
1013 withClient:(int)client
1014 withPosition:(NSDictionary*)position {
1015 NSString* stateString;
1016 switch (state) {
1017 case FlutterFloatingCursorDragStateStart:
1018 stateString = @"FloatingCursorDragState.start";
1019 break;
1020 case FlutterFloatingCursorDragStateUpdate:
1021 stateString = @"FloatingCursorDragState.update";
1022 break;
1023 case FlutterFloatingCursorDragStateEnd:
1024 stateString = @"FloatingCursorDragState.end";
1025 break;
1026 }
1027 [_textInputChannel.get() invokeMethod:@"TextInputClient.updateFloatingCursor"
1028 arguments:@[ @(client), stateString, position ]];
1029 }
1030
1031 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1032 performAction:(FlutterTextInputAction)action
1033 withClient:(int)client {
1034 NSString* actionString;
1035 switch (action) {
1036 case FlutterTextInputActionUnspecified:
1037 // Where did the term "unspecified" come from? iOS has a "default" and Android
1038 // has "unspecified." These 2 terms seem to mean the same thing but we need
1039 // to pick just one. "unspecified" was chosen because "default" is often a
1040 // reserved word in languages with switch statements (dart, java, etc).
1041 actionString = @"TextInputAction.unspecified";
1042 break;
1043 case FlutterTextInputActionDone:
1044 actionString = @"TextInputAction.done";
1045 break;
1046 case FlutterTextInputActionGo:
1047 actionString = @"TextInputAction.go";
1048 break;
1049 case FlutterTextInputActionSend:
1050 actionString = @"TextInputAction.send";
1051 break;
1052 case FlutterTextInputActionSearch:
1053 actionString = @"TextInputAction.search";
1054 break;
1055 case FlutterTextInputActionNext:
1056 actionString = @"TextInputAction.next";
1057 break;
1058 case FlutterTextInputActionContinue:
1059 actionString = @"TextInputAction.continueAction";
1060 break;
1061 case FlutterTextInputActionJoin:
1062 actionString = @"TextInputAction.join";
1063 break;
1064 case FlutterTextInputActionRoute:
1065 actionString = @"TextInputAction.route";
1066 break;
1067 case FlutterTextInputActionEmergencyCall:
1068 actionString = @"TextInputAction.emergencyCall";
1069 break;
1070 case FlutterTextInputActionNewline:
1071 actionString = @"TextInputAction.newline";
1072 break;
1073 }
1074 [_textInputChannel.get() invokeMethod:@"TextInputClient.performAction"
1075 arguments:@[ @(client), actionString ]];
1076 }
1077
1078 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1079 showAutocorrectionPromptRectForStart:(NSUInteger)start
1080 end:(NSUInteger)end
1081 withClient:(int)client {
1082 [_textInputChannel.get() invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
1083 arguments:@[ @(client), @(start), @(end) ]];
1084 }
1085
1086 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1087 willDismissEditMenuWithTextInputClient:(int)client {
1088 [_platformChannel.get() invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
1089 arguments:@[ @(client) ]];
1090 }
1091
1092 #pragma mark - FlutterViewEngineDelegate
1093
1094 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView showToolbar:(int)client {
1095 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1096 // the framework has finished transitioning to the Scribble channel.
1097 // https://github.com/flutter/flutter/pull/115296
1098 [_textInputChannel.get() invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
1099 }
1100
1101 - (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
1102 focusElement:(UIScribbleElementIdentifier)elementIdentifier
1103 atPoint:(CGPoint)referencePoint
1104 result:(FlutterResult)callback {
1105 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1106 // the framework has finished transitioning to the Scribble channel.
1107 // https://github.com/flutter/flutter/pull/115296
1108 [_textInputChannel.get()
1109 invokeMethod:@"TextInputClient.focusElement"
1110 arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
1111 result:callback];
1112 }
1113
1114 - (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
1115 requestElementsInRect:(CGRect)rect
1116 result:(FlutterResult)callback {
1117 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1118 // the framework has finished transitioning to the Scribble channel.
1119 // https://github.com/flutter/flutter/pull/115296
1120 [_textInputChannel.get()
1121 invokeMethod:@"TextInputClient.requestElementsInRect"
1122 arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
1123 result:callback];
1124 }
1125
1126 - (void)flutterTextInputViewScribbleInteractionBegan:(FlutterTextInputView*)textInputView {
1127 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1128 // the framework has finished transitioning to the Scribble channel.
1129 // https://github.com/flutter/flutter/pull/115296
1130 [_textInputChannel.get() invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
1131 }
1132
1133 - (void)flutterTextInputViewScribbleInteractionFinished:(FlutterTextInputView*)textInputView {
1134 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1135 // the framework has finished transitioning to the Scribble channel.
1136 // https://github.com/flutter/flutter/pull/115296
1137 [_textInputChannel.get() invokeMethod:@"TextInputClient.scribbleInteractionFinished"
1138 arguments:nil];
1139 }
1140
1141 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1142 insertTextPlaceholderWithSize:(CGSize)size
1143 withClient:(int)client {
1144 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1145 // the framework has finished transitioning to the Scribble channel.
1146 // https://github.com/flutter/flutter/pull/115296
1147 [_textInputChannel.get() invokeMethod:@"TextInputClient.insertTextPlaceholder"
1148 arguments:@[ @(client), @(size.width), @(size.height) ]];
1149 }
1150
1151 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1152 removeTextPlaceholder:(int)client {
1153 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1154 // the framework has finished transitioning to the Scribble channel.
1155 // https://github.com/flutter/flutter/pull/115296
1156 [_textInputChannel.get() invokeMethod:@"TextInputClient.removeTextPlaceholder"
1157 arguments:@[ @(client) ]];
1158 }
1159
1160 - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1161 didResignFirstResponderWithTextInputClient:(int)client {
1162 // When flutter text input view resign first responder, send a message to
1163 // framework to ensure the focus state is correct. This is useful when close
1164 // keyboard from platform side.
1165 [_textInputChannel.get() invokeMethod:@"TextInputClient.onConnectionClosed"
1166 arguments:@[ @(client) ]];
1167
1168 // Platform view's first responder detection logic:
1169 //
1170 // All text input widgets (e.g. EditableText) are backed by a dummy UITextInput view
1171 // in the TextInputPlugin. When this dummy UITextInput view resigns first responder,
1172 // check if any platform view becomes first responder. If any platform view becomes
1173 // first responder, send a "viewFocused" channel message to inform the framework to un-focus
1174 // the previously focused text input.
1175 //
1176 // Caveat:
1177 // 1. This detection logic does not cover the scenario when a platform view becomes
1178 // first responder without any flutter text input resigning its first responder status
1179 // (e.g. user tapping on platform view first). For now it works fine because the TextInputPlugin
1180 // does not track the focused platform view id (which is different from Android implementation).
1181 //
1182 // 2. This detection logic assumes that all text input widgets are backed by a dummy
1183 // UITextInput view in the TextInputPlugin, which may not hold true in the future.
1184
1185 // Have to check in the next run loop, because iOS requests the previous first responder to
1186 // resign before requesting the next view to become first responder.
1187 dispatch_async(dispatch_get_main_queue(), ^(void) {
1188 long platform_view_id = self.platformViewsController->FindFirstResponderPlatformViewId();
1189 if (platform_view_id == -1) {
1190 return;
1191 }
1192
1193 [_platformViewsChannel.get() invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
1194 });
1195 }
1196
1197 #pragma mark - Undo Manager Delegate
1198
1199 - (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
1200 NSString* action = (direction == FlutterUndoRedoDirectionUndo) ? @"undo" : @"redo";
1201 [_undoManagerChannel.get() invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
1202 }
1203
1204 - (UIView<UITextInput>*)activeTextInputView {
1205 return [[self textInputPlugin] textInputView];
1206 }
1207
1208 - (NSUndoManager*)undoManager {
1209 return self.viewController.undoManager;
1210 }
1211
1212 #pragma mark - Screenshot Delegate
1213
1214 - (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
1215 asBase64Encoded:(BOOL)base64Encode {
1216 FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
1217 return _shell->Screenshot(type, base64Encode);
1218 }
1219
1220 - (void)flutterViewAccessibilityDidCall {
1221 if (self.viewController.view.accessibilityElements == nil) {
1222 [self ensureSemanticsEnabled];
1223 }
1224 }
1225
1226 - (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
1227 return _binaryMessenger;
1228 }
1229
1230 - (NSObject<FlutterTextureRegistry>*)textureRegistry {
1231 return _textureRegistry;
1232 }
1233
1234 // For test only. Ideally we should create a dependency injector for all dependencies and
1235 // remove this.
1236 - (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger {
1237 // Discard the previous messenger and keep the new one.
1238 if (binaryMessenger != _binaryMessenger) {
1239 _binaryMessenger.parent = nil;
1240 [_binaryMessenger release];
1241 _binaryMessenger = [binaryMessenger retain];
1242 }
1243 }
1244
1245 #pragma mark - FlutterBinaryMessenger
1246
1247 - (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
1248 [self sendOnChannel:channel message:message binaryReply:nil];
1249 }
1250
1251 - (void)sendOnChannel:(NSString*)channel
1252 message:(NSData*)message
1253 binaryReply:(FlutterBinaryReply)callback {
1254 NSParameterAssert(channel);
1255 NSAssert(_shell && _shell->IsSetup(),
1256 @"Sending a message before the FlutterEngine has been run.");
1257 fml::RefPtr<flutter::PlatformMessageResponseDarwin> response =
1258 (callback == nil) ? nullptr
1259 : fml::MakeRefCounted<flutter::PlatformMessageResponseDarwin>(
1260 ^(NSData* reply) {
1261 callback(reply);
1262 },
1263 _shell->GetTaskRunners().GetPlatformTaskRunner());
1264 std::unique_ptr<flutter::PlatformMessage> platformMessage =
1265 (message == nil) ? std::make_unique<flutter::PlatformMessage>(channel.UTF8String, response)
1266 : std::make_unique<flutter::PlatformMessage>(
1267 channel.UTF8String, flutter::CopyNSDataToMapping(message), response);
1268
1269 _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
1270 // platformMessage takes ownership of response.
1271 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1272 }
1273
1274 - (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
1275 return flutter::PlatformMessageHandlerIos::MakeBackgroundTaskQueue();
1276 }
1277
1278 - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
1279 binaryMessageHandler:
1280 (FlutterBinaryMessageHandler)handler {
1281 return [self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
1282 }
1283
1284 - (FlutterBinaryMessengerConnection)
1285 setMessageHandlerOnChannel:(NSString*)channel
1286 binaryMessageHandler:(FlutterBinaryMessageHandler)handler
1287 taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
1288 NSParameterAssert(channel);
1289 if (_shell && _shell->IsSetup()) {
1290 self.iosPlatformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
1291 handler, taskQueue);
1292 return _connections->AquireConnection(channel.UTF8String);
1293 } else {
1294 NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
1295 // Setting a handler to nil for a channel that has not yet been set up is a no-op.
1296 return flutter::ConnectionCollection::MakeErrorConnection(-1);
1297 }
1298 }
1299
1300 - (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
1301 if (_shell && _shell->IsSetup()) {
1302 std::string channel = _connections->CleanupConnection(connection);
1303 if (!channel.empty()) {
1304 self.iosPlatformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.c_str(), nil,
1305 nil);
1306 }
1307 }
1308 }
1309
1310 #pragma mark - FlutterTextureRegistry
1311
1312 - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture {
1313 int64_t textureId = _nextTextureId++;
1314 self.iosPlatformView->RegisterExternalTexture(textureId, texture);
1315 return textureId;
1316 }
1317
1318 - (void)unregisterTexture:(int64_t)textureId {
1319 _shell->GetPlatformView()->UnregisterTexture(textureId);
1320 }
1321
1322 - (void)textureFrameAvailable:(int64_t)textureId {
1323 _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
1324 }
1325
1326 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1327 return [FlutterDartProject lookupKeyForAsset:asset];
1328 }
1329
1330 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1331 return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
1332 }
1333
1334 - (id<FlutterPluginRegistry>)pluginRegistry {
1335 return self;
1336 }
1337
1338 #pragma mark - FlutterPluginRegistry
1339
1340 - (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
1341 NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
1342 self.pluginPublications[pluginKey] = [NSNull null];
1343 FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey
1344 flutterEngine:self];
1345 self.registrars[pluginKey] = result;
1346 return [result autorelease];
1347 }
1348
1349 - (BOOL)hasPlugin:(NSString*)pluginKey {
1350 return _pluginPublications[pluginKey] != nil;
1351 }
1352
1353 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1354 return _pluginPublications[pluginKey];
1355 }
1356
1357 #pragma mark - Notifications
1358
1359 #if APPLICATION_EXTENSION_API_ONLY
1360 - (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1361 [self flutterWillEnterForeground:notification];
1362 }
1363
1364 - (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1365 [self flutterDidEnterBackground:notification];
1366 }
1367 #else
1368 - (void)applicationWillEnterForeground:(NSNotification*)notification {
1369 [self flutterWillEnterForeground:notification];
1370 }
1371
1372 - (void)applicationDidEnterBackground:(NSNotification*)notification {
1373 [self flutterDidEnterBackground:notification];
1374 }
1375 #endif
1376
1377 - (void)flutterWillEnterForeground:(NSNotification*)notification {
1378 [self setIsGpuDisabled:NO];
1379 }
1380
1381 - (void)flutterDidEnterBackground:(NSNotification*)notification {
1382 [self setIsGpuDisabled:YES];
1383 [self notifyLowMemory];
1384 }
1385
1386 - (void)onMemoryWarning:(NSNotification*)notification {
1387 [self notifyLowMemory];
1388 }
1389
1390 - (void)setIsGpuDisabled:(BOOL)value {
1391 if (_shell) {
1392 _shell->SetGpuAvailability(value ? flutter::GpuAvailability::kUnavailable
1393 : flutter::GpuAvailability::kAvailable);
1394 }
1395 _isGpuDisabled = value;
1396 }
1397
1398 #pragma mark - Locale updates
1399
1400 - (void)onLocaleUpdated:(NSNotification*)notification {
1401 // Get and pass the user's preferred locale list to dart:ui.
1402 NSMutableArray<NSString*>* localeData = [[[NSMutableArray alloc] init] autorelease];
1403 NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
1404 for (NSString* localeID in preferredLocales) {
1405 NSLocale* locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease];
1406 NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
1407 NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
1408 NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
1409 NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
1410 if (!languageCode) {
1411 continue;
1412 }
1413 [localeData addObject:languageCode];
1414 [localeData addObject:(countryCode ? countryCode : @"")];
1415 [localeData addObject:(scriptCode ? scriptCode : @"")];
1416 [localeData addObject:(variantCode ? variantCode : @"")];
1417 }
1418 if (localeData.count == 0) {
1419 return;
1420 }
1421 [self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
1422 }
1423
1424 - (void)waitForFirstFrame:(NSTimeInterval)timeout
1425 callback:(void (^_Nonnull)(BOOL didTimeout))callback {
1426 dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
1427 dispatch_async(queue, ^{
1428 fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
1429 BOOL didTimeout =
1430 self.shell.WaitForFirstFrame(waitTime).code() == fml::StatusCode::kDeadlineExceeded;
1431 dispatch_async(dispatch_get_main_queue(), ^{
1432 callback(didTimeout);
1433 });
1434 });
1435 }
1436
1437 - (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
1438 libraryURI:(/*nullable*/ NSString*)libraryURI
1439 initialRoute:(/*nullable*/ NSString*)initialRoute
1440 entrypointArgs:(/*nullable*/ NSArray<NSString*>*)entrypointArgs {
1441 NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
1442 FlutterEngine* result = [[FlutterEngine alloc] initWithName:_labelPrefix
1443 project:_dartProject.get()
1444 allowHeadlessExecution:_allowHeadlessExecution];
1445 flutter::RunConfiguration configuration =
1446 [_dartProject.get() runConfigurationForEntrypoint:entrypoint
1447 libraryOrNil:libraryURI
1448 entrypointArgs:entrypointArgs];
1449
1450 fml::WeakPtr<flutter::PlatformView> platform_view = _shell->GetPlatformView();
1451 FML_DCHECK(platform_view);
1452 // Static-cast safe since this class always creates PlatformViewIOS instances.
1453 flutter::PlatformViewIOS* ios_platform_view =
1454 static_cast<flutter::PlatformViewIOS*>(platform_view.get());
1455 std::shared_ptr<flutter::IOSContext> context = ios_platform_view->GetIosContext();
1456 FML_DCHECK(context);
1457
1458 // Lambda captures by pointers to ObjC objects are fine here because the
1459 // create call is synchronous.
1460 flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
1461 [result, context](flutter::Shell& shell) {
1462 [result recreatePlatformViewController];
1463 result->_platformViewsController->SetTaskRunner(
1464 shell.GetTaskRunners().GetPlatformTaskRunner());
1465 return std::make_unique<flutter::PlatformViewIOS>(
1466 shell, context, result->_platformViewsController, shell.GetTaskRunners());
1467 };
1468
1469 flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
1470 [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
1471
1472 std::string cppInitialRoute;
1473 if (initialRoute) {
1474 cppInitialRoute = [initialRoute UTF8String];
1475 }
1476
1477 std::unique_ptr<flutter::Shell> shell = _shell->Spawn(
1478 std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1479
1480 result->_threadHost = _threadHost;
1481 result->_profiler = _profiler;
1482 result->_profiler_metrics = _profiler_metrics;
1483 result->_isGpuDisabled = _isGpuDisabled;
1484 [result setUpShell:std::move(shell) withVMServicePublication:NO];
1485 return [result autorelease];
1486 }
1487
1488 - (const flutter::ThreadHost&)threadHost {
1489 return *_threadHost;
1490 }
1491
1492 - (FlutterDartProject*)project {
1493 return _dartProject.get();
1494 }
1495
1496 - (BOOL)isUsingImpeller {
1497 return self.project.isImpellerEnabled;
1498 }
1499
1500 @end
1501
1502 @implementation FlutterEngineRegistrar {
1503 NSString* _pluginKey;
1504 }
1505
1506 - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
1507 self = [super init];
1508 NSAssert(self, @"Super init cannot be nil");
1509 _pluginKey = [pluginKey copy];
1510 _flutterEngine = flutterEngine;
1511 return self;
1512 }
1513
1514 - (void)dealloc {
1515 [_pluginKey release];
1516 [super dealloc];
1517 }
1518
1519 - (NSObject<FlutterBinaryMessenger>*)messenger {
1520 return _flutterEngine.binaryMessenger;
1521 }
1522
1523 - (NSObject<FlutterTextureRegistry>*)textures {
1524 return _flutterEngine.textureRegistry;
1525 }
1526
1527 - (void)publish:(NSObject*)value {
1528 _flutterEngine.pluginPublications[_pluginKey] = value;
1529 }
1530
1531 - (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
1532 channel:(FlutterMethodChannel*)channel {
1533 [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1534 [delegate handleMethodCall:call result:result];
1535 }];
1536 }
1537
1538 - (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate
1539 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in plugins used in app extensions") {
1540 id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
1541 if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifeCycleProvider)]) {
1542 id<FlutterAppLifeCycleProvider> lifeCycleProvider =
1543 (id<FlutterAppLifeCycleProvider>)appDelegate;
1544 [lifeCycleProvider addApplicationLifeCycleDelegate:delegate];
1545 }
1546 }
1547
1548 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1549 return [_flutterEngine lookupKeyForAsset:asset];
1550 }
1551
1552 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1553 return [_flutterEngine lookupKeyForAsset:asset fromPackage:package];
1554 }
1555
1556 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1557 withId:(NSString*)factoryId {
1558 [self registerViewFactory:factory
1559 withId:factoryId
1560 gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
1561 }
1562
1563 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1564 withId:(NSString*)factoryId
1565 gestureRecognizersBlockingPolicy:
1566 (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy {
1567 [_flutterEngine platformViewsController]->RegisterViewFactory(factory, factoryId,
1568 gestureRecognizersBlockingPolicy);
1569 }
1570
1571 @end
_restorationChannel
fml::scoped_nsobject< FlutterMethodChannel > _restorationChannel
Definition: FlutterEngine.mm:139
FlutterTextureRegistryRelay::parent
NSObject< FlutterTextureRegistry > * parent
Definition: FlutterTextureRegistryRelay.h:25
_weakFactory
std::unique_ptr< fml::WeakNSObjectFactory< FlutterEngine > > _weakFactory
Definition: FlutterEngine.mm:121
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:143
FlutterTextInputDelegate-p
Definition: FlutterTextInputDelegate.h:37
_viewController
fml::WeakNSObject< FlutterViewController > _viewController
Definition: FlutterEngine.mm:123
FlutterDefaultInitialRoute
NSString *const FlutterDefaultInitialRoute
Definition: FlutterEngine.mm:82
FlutterTextInputPlugin::indirectScribbleDelegate
id< FlutterIndirectScribbleDelegate > indirectScribbleDelegate
Definition: FlutterTextInputPlugin.h:37
FlutterSpellCheckPlugin
Definition: FlutterSpellCheckPlugin.h:11
FlutterDefaultDartEntrypoint
NSString *const FlutterDefaultDartEntrypoint
Definition: FlutterEngine.mm:81
_labelPrefix
NSString * _labelPrefix
Definition: FlutterEngine.mm:120
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:57
FlutterMethodChannel
Definition: FlutterChannels.h:220
FlutterEngineRegistrar::flutterEngine
FlutterEngine * flutterEngine
Definition: FlutterEngine.mm:91
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:146
_textInputPlugin
fml::scoped_nsobject< FlutterTextInputPlugin > _textInputPlugin
Definition: FlutterEngine.mm:133
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:138
connection_collection.h
_textInputChannel
fml::scoped_nsobject< FlutterMethodChannel > _textInputChannel
Definition: FlutterEngine.mm:142
FlutterEngine_Internal.h
command_line.h
+[FlutterDartProject lookupKeyForAsset:]
NSString * lookupKeyForAsset:(NSString *asset)
Definition: FlutterDartProject.mm:384
FlutterError
Definition: FlutterCodecs.h:246
kNumProfilerSamplesPerSec
static constexpr int kNumProfilerSamplesPerSec
Definition: FlutterEngine.mm:88
FlutterDartVMServicePublisher.h
-[FlutterPlatformPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterPlatformPlugin.mm:106
-[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:128
flutter::CopyNSDataToMapping
fml::MallocMapping CopyNSDataToMapping(NSData *data)
Definition: buffer_conversions.mm:30
_settingsChannel
fml::scoped_nsobject< FlutterBasicMessageChannel > _settingsChannel
Definition: FlutterEngine.mm:148
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:158
FlutterPluginRegistrar-p
Definition: FlutterPlugin.h:283
-[FlutterTextInputPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterTextInputPlugin.mm:2391
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:124
_spellCheckChannel
fml::scoped_nsobject< FlutterMethodChannel > _spellCheckChannel
Definition: FlutterEngine.mm:145
FlutterIndirectScribbleDelegate-p
Definition: FlutterIndirectScribbleDelegate.h:13
-[FlutterTextInputPlugin setUpIndirectScribbleInteraction:]
void setUpIndirectScribbleInteraction:(id< FlutterViewResponder > viewResponder)
Definition: FlutterTextInputPlugin.mm:3024
viewController
FlutterViewController * viewController
Definition: FlutterTextInputPluginTest.mm:92
FlutterBinaryMessageHandler
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
Definition: FlutterBinaryMessenger.h:30
-[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:87
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:135
_undoManagerPlugin
fml::scoped_nsobject< FlutterUndoManagerPlugin > _undoManagerPlugin
Definition: FlutterEngine.mm:134
FlutterSpellCheckPlugin.h
flutter
Definition: accessibility_bridge.h:28
_scribbleChannel
fml::scoped_nsobject< FlutterMethodChannel > _scribbleChannel
Definition: FlutterEngine.mm:144
_textureRegistry
FlutterTextureRegistryRelay * _textureRegistry
Definition: FlutterEngine.mm:157
IOSPlatformThreadConfigSetter
static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig &config)
Definition: FlutterEngine.mm:47
FlutterTextInputPlugin
Definition: FlutterTextInputPlugin.h:33
_systemChannel
fml::scoped_nsobject< FlutterBasicMessageChannel > _systemChannel
Definition: FlutterEngine.mm:147
_profiler
std::shared_ptr< flutter::SamplingProfiler > _profiler
Definition: FlutterEngine.mm:129
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:149
FlutterIndirectScribbleDelegate.h
FlutterPlatformPlugin.h
_renderingApi
flutter::IOSRenderingAPI _renderingApi
Definition: FlutterEngine.mm:127
FlutterTexture
Definition: FlutterMetalLayer.mm:59
-[FlutterPlugin-p handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
_binaryMessenger
FlutterBinaryMessengerRelay * _binaryMessenger
Definition: FlutterEngine.mm:156
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:150
_shell
std::unique_ptr< flutter::Shell > _shell
Definition: FlutterEngine.mm:119
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:155
FlutterView
Definition: FlutterView.h:34
_platformChannel
fml::scoped_nsobject< FlutterMethodChannel > _platformChannel
Definition: FlutterEngine.mm:140
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:393
FlutterEngineRegistrar
Definition: FlutterEngine.mm:90
platform_view_ios.h
flutter::PlatformViewsController
Composites Flutter UI and overlay layers alongside embedded UIViews.
Definition: platform_views_controller.h:31
_nextTextureId
int64_t _nextTextureId
Definition: FlutterEngine.mm:152
FlutterEngine(Test)::enableEmbedderAPI
BOOL enableEmbedderAPI
Definition: FlutterEngine_Test.h:26
FlutterDartProject
Definition: FlutterDartProject.mm:258
FlutterTextureRegistryRelay.h
_localizationChannel
fml::scoped_nsobject< FlutterMethodChannel > _localizationChannel
Definition: FlutterEngine.mm:137
_allowHeadlessExecution
BOOL _allowHeadlessExecution
Definition: FlutterEngine.mm:154
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:116
_platformViewsController
std::shared_ptr< flutter::PlatformViewsController > _platformViewsController
Definition: FlutterEngine.mm:126
FlutterUndoManagerDelegate.h
FlutterStandardMethodCodec
Definition: FlutterCodecs.h:469
kFlutterEngineWillDealloc
NSString *const kFlutterEngineWillDealloc
Definition: FlutterEngine.mm:86
FlutterBinaryMessengerConnection
int64_t FlutterBinaryMessengerConnection
Definition: FlutterBinaryMessenger.h:32
_restorationPlugin
fml::scoped_nsobject< FlutterRestorationPlugin > _restorationPlugin
Definition: FlutterEngine.mm:136
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
_platformViewsChannel
fml::scoped_nsobject< FlutterMethodChannel > _platformViewsChannel
Definition: FlutterEngine.mm:141
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()
_platformPlugin
fml::scoped_nsobject< FlutterPlatformPlugin > _platformPlugin
Definition: FlutterEngine.mm:132
-[FlutterSpellCheckPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterSpellCheckPlugin.mm:38
FlutterJSONMessageCodec
Definition: FlutterCodecs.h:81