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