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