5 #include <UIKit/UIKit.h>
6 #include "common/settings.h"
7 #define FML_USED_ON_EMBEDDER
13 #include "flutter/common/constants.h"
14 #include "flutter/fml/message_loop.h"
15 #include "flutter/fml/platform/darwin/platform_version.h"
16 #include "flutter/fml/trace_event.h"
17 #include "flutter/runtime/ptrace_check.h"
18 #include "flutter/shell/common/engine.h"
19 #include "flutter/shell/common/platform_view.h"
20 #include "flutter/shell/common/shell.h"
21 #include "flutter/shell/common/switches.h"
22 #include "flutter/shell/common/thread_host.h"
23 #include "flutter/shell/common/variable_refresh_rate_display.h"
24 #import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
27 #import "flutter/shell/platform/darwin/ios/InternalFlutterSwift/InternalFlutterSwift.h"
45 #include "flutter/shell/profiling/sampling_profiler.h"
53 fml::Thread::SetCurrentThreadName(config);
56 switch (config.priority) {
57 case fml::Thread::ThreadPriority::kBackground: {
58 pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
59 [[NSThread currentThread] setThreadPriority:0];
62 case fml::Thread::ThreadPriority::kNormal: {
63 pthread_set_qos_class_self_np(QOS_CLASS_DEFAULT, 0);
64 [[NSThread currentThread] setThreadPriority:0.5];
67 case fml::Thread::ThreadPriority::kRaster:
68 case fml::Thread::ThreadPriority::kDisplay: {
69 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
70 [[NSThread currentThread] setThreadPriority:1.0];
73 pthread_t thread = pthread_self();
74 if (!pthread_getschedparam(thread, &policy, ¶m)) {
75 param.sched_priority = 50;
76 pthread_setschedparam(thread, policy, ¶m);
83 #pragma mark - Public exported constants
88 #pragma mark - Internal constants
97 @property(nonatomic, readonly) NSString*
key;
99 - (instancetype)initWithKey:(NSString*)key flutterEngine:(
FlutterEngine*)flutterEngine;
116 #pragma mark - Properties
119 @property(nonatomic, readonly, copy) NSString* labelPrefix;
120 @property(nonatomic, readonly, assign) BOOL allowHeadlessExecution;
121 @property(nonatomic, readonly, assign) BOOL restorationEnabled;
129 @property(nonatomic, readonly)
130 NSMutableDictionary<NSString*, FlutterEngineBaseRegistrar*>* registrars;
132 @property(nonatomic, readwrite, copy) NSString*
isolateId;
133 @property(nonatomic, copy) NSString* initialRoute;
134 @property(nonatomic, strong) id<NSObject> flutterViewControllerWillDeallocObserver;
136 @property(nonatomic, strong) FlutterConnectionCollection* connections;
137 @property(nonatomic, assign) int64_t nextTextureId;
139 #pragma mark - Channel properties
164 #pragma mark - Embedder API properties
181 _appRegistrar = [engine registrarForApplication:kFlutterApplicationRegistrarKey];
186 - (NSObject<FlutterPluginRegistry>*)pluginRegistry {
196 std::shared_ptr<flutter::ThreadHost> _threadHost;
210 - (int64_t)engineIdentifier {
211 return reinterpret_cast<int64_t
>((__bridge
void*)
self);
214 - (instancetype)init {
215 return [
self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
218 - (instancetype)initWithName:(NSString*)labelPrefix {
219 return [
self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
222 - (instancetype)initWithName:(NSString*)labelPrefix project:(
FlutterDartProject*)project {
223 return [
self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
226 - (instancetype)initWithName:(NSString*)labelPrefix
228 allowHeadlessExecution:(BOOL)allowHeadlessExecution {
229 return [
self initWithName:labelPrefix
231 allowHeadlessExecution:allowHeadlessExecution
232 restorationEnabled:NO];
235 - (instancetype)initWithName:(NSString*)labelPrefix
237 allowHeadlessExecution:(BOOL)allowHeadlessExecution
238 restorationEnabled:(BOOL)restorationEnabled {
240 NSAssert(
self,
@"Super init cannot be nil");
241 NSAssert(labelPrefix,
@"labelPrefix is required");
244 _allowHeadlessExecution = allowHeadlessExecution;
245 _labelPrefix = [labelPrefix copy];
248 _enableEmbedderAPI = _dartProject.
settings.enable_embedder_api;
249 if (_enableEmbedderAPI) {
250 NSLog(
@"============== iOS: enable_embedder_api is on ==============");
251 _embedderAPI.struct_size =
sizeof(FlutterEngineProcTable);
252 FlutterEngineGetProcAddresses(&_embedderAPI);
255 if (!EnableTracingIfNecessary(_dartProject.settings)) {
257 @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
258 @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
259 @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
260 @"profile and release mode apps can be launched from the home screen.");
264 _pluginPublications = [[NSMutableDictionary alloc] init];
265 _registrars = [[NSMutableDictionary alloc] init];
266 [
self recreatePlatformViewsController];
269 _connections = [[FlutterConnectionCollection alloc] init];
271 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
272 [center addObserver:self
273 selector:@selector(onMemoryWarning:)
274 name:UIApplicationDidReceiveMemoryWarningNotification
277 [
self setUpLifecycleNotifications:center];
279 [center addObserver:self
280 selector:@selector(onLocaleUpdated:)
281 name:NSCurrentLocaleDidChangeNotification
290 NSAssert([[NSThread currentThread] isMainThread],
@"Must be called on the main thread.");
291 return (__bridge
FlutterEngine*)
reinterpret_cast<void*
>(identifier);
294 - (void)setUpLifecycleNotifications:(NSNotificationCenter*)center {
296 [center addObserver:self
297 selector:@selector(sceneWillConnect:)
298 name:UISceneWillConnectNotification
301 [center addObserver:self
302 selector:@selector(sceneWillEnterForeground:)
303 name:UISceneWillEnterForegroundNotification
305 [center addObserver:self
306 selector:@selector(sceneDidEnterBackground:)
307 name:UISceneDidEnterBackgroundNotification
311 [center addObserver:self
312 selector:@selector(applicationWillEnterForeground:)
313 name:UIApplicationWillEnterForegroundNotification
315 [center addObserver:self
316 selector:@selector(applicationDidEnterBackground:)
317 name:UIApplicationDidEnterBackgroundNotification
321 - (void)sceneWillConnect:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
325 UIScene* scene = notification.object;
335 if (sceneLifeCycleDelegate != nil) {
336 return [sceneLifeCycleDelegate engine:self receivedConnectNotificationFor:scene];
341 - (void)recreatePlatformViewsController {
346 - (
flutter::IOSRenderingAPI)platformViewsRenderingAPI {
353 [_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
354 if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
356 if ([registrar conformsToProtocol:@protocol(FlutterPluginRegistrar)]) {
357 [object detachFromEngineForRegistrar:((id<FlutterPluginRegistrar>)registrar)];
365 [_registrars enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineBaseRegistrar* registrar,
367 registrar.flutterEngine = nil;
373 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
374 if (_flutterViewControllerWillDeallocObserver) {
375 [center removeObserver:_flutterViewControllerWillDeallocObserver];
377 [center removeObserver:self];
385 - (void)updateViewportMetrics:(
flutter::ViewportMetrics)viewportMetrics {
386 if (!
self.platformView) {
389 self.platformView->SetViewportMetrics(flutter::kFlutterImplicitViewId, viewportMetrics);
392 - (void)dispatchPointerDataPacket:(std::unique_ptr<
flutter::PointerDataPacket>)packet {
393 if (!
self.platformView) {
396 self.platformView->DispatchPointerDataPacket(std::move(packet));
399 - (BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(
flutter::PointData)location
400 viewId:(uint64_t)viewId {
401 if (!
self.platformView) {
404 return self.platformView->HitTest(viewId, location).has_platform_view;
407 - (void)installFirstFrameCallback:(
void (^)(
void))block {
408 if (!
self.platformView) {
413 self.
platformView->SetNextFrameCallback([weakSelf, block] {
422 [strongSelf.platformTaskRunner postTask:^{
428 - (void)enableSemantics:(BOOL)enabled withFlags:(int64_t)flags {
429 if (!
self.platformView) {
433 self.platformView->SetAccessibilityFeatures(flags);
436 - (void)notifyViewCreated {
437 if (!
self.platformView) {
440 self.platformView->NotifyCreated();
443 - (void)notifyViewDestroyed {
444 if (!
self.platformView) {
447 self.platformView->NotifyDestroyed();
450 - (
flutter::PlatformViewIOS*)platformView {
469 - (void)sendKeyEvent:(const FlutterKeyEvent&)event
470 callback:(FlutterKeyEventCallback)callback
471 userData:(
void*)userData API_AVAILABLE(ios(13.4)) {
472 if (@available(iOS 13.4, *)) {
476 if (!
self.platformView) {
479 const char* character =
event.character;
481 flutter::KeyData key_data;
483 key_data.timestamp = (uint64_t)event.timestamp;
484 switch (event.type) {
485 case kFlutterKeyEventTypeUp:
486 key_data.type = flutter::KeyEventType::kUp;
488 case kFlutterKeyEventTypeDown:
489 key_data.type = flutter::KeyEventType::kDown;
491 case kFlutterKeyEventTypeRepeat:
492 key_data.type = flutter::KeyEventType::kRepeat;
495 key_data.physical =
event.physical;
496 key_data.logical =
event.logical;
497 key_data.synthesized =
event.synthesized;
499 auto packet = std::make_unique<flutter::KeyDataPacket>(key_data, character);
500 NSData* message = [NSData dataWithBytes:packet->data().data() length:packet->data().size()];
502 auto response = ^(NSData* reply) {
503 if (callback ==
nullptr) {
506 BOOL handled = FALSE;
507 if (reply.length == 1 && *
reinterpret_cast<const uint8_t*
>(reply.bytes) == 1) {
510 callback(handled, userData);
513 [
self sendOnChannel:kFlutterKeyDataChannel message:message binaryReply:response];
516 - (void)ensureSemanticsEnabled {
517 if (!
self.platformView) {
520 self.platformView->SetSemanticsEnabled(
true);
524 FML_DCHECK(
self.platformView);
526 self.platformView->SetOwnerViewController(_viewController);
527 [
self maybeSetupPlatformViewChannels];
528 [
self updateDisplays];
533 self.flutterViewControllerWillDeallocObserver =
534 [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
535 object:viewController
536 queue:[NSOperationQueue mainQueue]
537 usingBlock:^(NSNotification* note) {
538 [weakSelf notifyViewControllerDeallocated];
541 self.flutterViewControllerWillDeallocObserver = nil;
542 [
self notifyLowMemory];
547 FML_DCHECK(
self.platformView);
548 self.platformView->attachView();
551 - (void)setFlutterViewControllerWillDeallocObserver:(
id<NSObject>)observer {
552 if (observer != _flutterViewControllerWillDeallocObserver) {
553 if (_flutterViewControllerWillDeallocObserver) {
554 [[NSNotificationCenter defaultCenter]
555 removeObserver:_flutterViewControllerWillDeallocObserver];
557 _flutterViewControllerWillDeallocObserver = observer;
561 - (void)notifyViewControllerDeallocated {
562 [
self.lifecycleChannel sendMessage:@"AppLifecycleState.detached"];
563 self.textInputPlugin.viewController = nil;
564 if (!
self.allowHeadlessExecution) {
565 [
self destroyContext];
566 }
else if (
self.platformView) {
567 self.platformView->SetOwnerViewController({});
569 [
self.textInputPlugin resetViewResponder];
570 _viewController = nil;
573 - (void)destroyContext {
574 [
self resetChannels];
575 self.isolateId = nil;
579 _platformViewsController = nil;
585 - (NSURL*)vmServiceUrl {
586 return self.publisher.url;
589 - (void)resetChannels {
590 self.localizationChannel = nil;
591 self.navigationChannel = nil;
592 self.restorationChannel = nil;
593 self.platformChannel = nil;
594 self.statusBarChannel = nil;
595 self.platformViewsChannel = nil;
596 self.textInputChannel = nil;
597 self.undoManagerChannel = nil;
598 self.scribbleChannel = nil;
599 self.lifecycleChannel = nil;
600 self.systemChannel = nil;
601 self.settingsChannel = nil;
602 self.keyEventChannel = nil;
603 self.spellCheckChannel = nil;
606 - (void)startProfiler {
607 FML_DCHECK(!_threadHost->name_prefix.empty());
608 _profiler = std::make_shared<flutter::SamplingProfiler>(
609 _threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(),
611 flutter::ProfilerMetricsIOS profiler_metrics;
612 return profiler_metrics.GenerateSample();
621 - (void)setUpChannels {
625 [_binaryMessenger setMessageHandlerOnChannel:@"flutter/isolate"
626 binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
635 binaryMessenger:self.binaryMessenger
638 self.navigationChannel =
640 binaryMessenger:self.binaryMessenger
643 if ([_initialRoute length] > 0) {
645 [
self.navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
649 self.restorationChannel =
651 binaryMessenger:self.binaryMessenger
654 self.platformChannel =
656 binaryMessenger:self.binaryMessenger
659 self.statusBarChannel =
661 binaryMessenger:self.binaryMessenger
663 [
self.statusBarChannel resizeChannelBuffer:0];
665 self.platformViewsChannel =
667 binaryMessenger:self.binaryMessenger
670 self.textInputChannel =
672 binaryMessenger:self.binaryMessenger
675 self.undoManagerChannel =
677 binaryMessenger:self.binaryMessenger
680 self.scribbleChannel =
682 binaryMessenger:self.binaryMessenger
685 self.spellCheckChannel =
687 binaryMessenger:self.binaryMessenger
690 self.lifecycleChannel =
692 binaryMessenger:self.binaryMessenger
697 binaryMessenger:self.binaryMessenger
700 self.settingsChannel =
702 binaryMessenger:self.binaryMessenger
705 self.keyEventChannel =
707 binaryMessenger:self.binaryMessenger
711 self.textInputPlugin.indirectScribbleDelegate =
self;
712 [
self.textInputPlugin setUpIndirectScribbleInteraction:self.viewController];
717 self.restorationPlugin =
719 restorationEnabled:self.restorationEnabled];
722 self.screenshotChannel =
724 binaryMessenger:self.binaryMessenger
727 [
self.screenshotChannel setMethodCallHandler:^(FlutterMethodCall* _Nonnull call,
728 FlutterResult _Nonnull result) {
730 if (!(strongSelf && strongSelf->_shell && strongSelf->_shell->IsSetup())) {
733 message:@"Requesting screenshot while engine is not running."
736 flutter::Rasterizer::Screenshot screenshot =
737 [strongSelf screenshot:flutter::Rasterizer::ScreenshotType::SurfaceData base64Encode:NO];
738 if (!screenshot.data) {
740 message:@"Unable to get screenshot."
744 NSData* data = [NSData dataWithBytes:screenshot.data->writable_data()
745 length:screenshot.data->size()];
746 NSString* format = [NSString stringWithUTF8String:screenshot.format.c_str()];
747 NSNumber* width = @(screenshot.frame_size.width);
748 NSNumber* height = @(screenshot.frame_size.height);
749 return result(@[ width, height, format ?: [NSNull null], data ]);
753 - (void)maybeSetupPlatformViewChannels {
754 if (
_shell &&
self.shell.IsSetup()) {
757 [
self.platformChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
758 [weakSelf.platformPlugin handleMethodCall:call result:result];
761 [
self.platformViewsChannel
762 setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
764 [weakSelf.platformViewsController onMethodCall:call result:result];
768 [
self.textInputChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
769 [weakSelf.textInputPlugin handleMethodCall:call result:result];
772 [
self.undoManagerChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
773 [weakSelf.undoManagerPlugin handleMethodCall:call result:result];
776 [
self.spellCheckChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
777 [weakSelf.spellCheckPlugin handleMethodCall:call result:result];
782 - (
flutter::Rasterizer::Screenshot)screenshot:(
flutter::Rasterizer::ScreenshotType)type
783 base64Encode:(
bool)base64Encode {
784 return self.shell.Screenshot(type, base64Encode);
787 - (void)launchEngine:(NSString*)entrypoint
788 libraryURI:(NSString*)libraryOrNil
789 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
791 flutter::RunConfiguration configuration =
792 [
self.dartProject runConfigurationForEntrypoint:entrypoint
793 libraryOrNil:libraryOrNil
794 entrypointArgs:entrypointArgs];
796 configuration.SetEngineId(
self.engineIdentifier);
797 self.shell.RunEngine(std::move(configuration));
800 - (void)setUpShell:(std::unique_ptr<
flutter::Shell>)shell
801 withVMServicePublication:(BOOL)doesVMServicePublication {
802 _shell = std::move(shell);
804 initWithTaskRunner:_shell->GetTaskRunners().GetPlatformTaskRunner()];
808 initWithTaskRunner:_shell->GetTaskRunners().GetRasterTaskRunner()];
810 [
self setUpChannels];
811 [
self onLocaleUpdated:nil];
812 [
self updateDisplays];
814 initWithEnableVMServicePublication:doesVMServicePublication];
815 [
self maybeSetupPlatformViewChannels];
816 _shell->SetGpuAvailability(_isGpuDisabled ? flutter::GpuAvailability::kUnavailable
817 : flutter::GpuAvailability::kAvailable);
820 + (BOOL)isProfilerEnabled {
821 bool profilerEnabled =
false;
822 #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
823 (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
824 profilerEnabled =
true;
826 return profilerEnabled;
829 + (NSString*)generateThreadLabel:(NSString*)labelPrefix {
830 static size_t s_shellCount = 0;
831 return [NSString stringWithFormat:@"%@.%zu", labelPrefix, ++s_shellCount];
834 static flutter::ThreadHost MakeThreadHost(NSString* thread_label,
835 const flutter::Settings& settings) {
838 fml::MessageLoop::EnsureInitializedForCurrentThread();
840 uint32_t threadHostType = flutter::ThreadHost::Type::kRaster | flutter::ThreadHost::Type::kIo;
841 if (settings.merged_platform_ui_thread != flutter::Settings::MergedPlatformUIThread::kEnabled) {
842 threadHostType |= flutter::ThreadHost::Type::kUi;
846 threadHostType = threadHostType | flutter::ThreadHost::Type::kProfiler;
849 flutter::ThreadHost::ThreadHostConfig host_config(thread_label.UTF8String, threadHostType,
852 host_config.ui_config =
853 fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
854 flutter::ThreadHost::Type::kUi, thread_label.UTF8String),
855 fml::Thread::ThreadPriority::kDisplay);
856 host_config.raster_config =
857 fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
858 flutter::ThreadHost::Type::kRaster, thread_label.UTF8String),
859 fml::Thread::ThreadPriority::kRaster);
861 host_config.io_config =
862 fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName(
863 flutter::ThreadHost::Type::kIo, thread_label.UTF8String),
864 fml::Thread::ThreadPriority::kNormal);
866 return (flutter::ThreadHost){host_config};
869 static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
871 FML_DCHECK(entrypoint) <<
"Must specify entrypoint if specifying library";
872 settings->advisory_script_entrypoint = entrypoint.UTF8String;
873 settings->advisory_script_uri = libraryURI.UTF8String;
874 }
else if (entrypoint) {
875 settings->advisory_script_entrypoint = entrypoint.UTF8String;
876 settings->advisory_script_uri = std::string(
"main.dart");
878 settings->advisory_script_entrypoint = std::string(
"main");
879 settings->advisory_script_uri = std::string(
"main.dart");
883 - (BOOL)createShell:(NSString*)entrypoint
884 libraryURI:(NSString*)libraryURI
885 initialRoute:(NSString*)initialRoute {
887 [FlutterLogger logWarning:@"This FlutterEngine was already invoked."];
891 self.initialRoute = initialRoute;
893 auto settings = [
self.dartProject settings];
894 if (initialRoute != nil) {
895 self.initialRoute = initialRoute;
896 }
else if (settings.route.empty() ==
false) {
897 self.initialRoute = [NSString stringWithUTF8String:settings.route.c_str()];
900 auto platformData = [
self.dartProject defaultPlatformData];
902 SetEntryPoint(&settings, entrypoint, libraryURI);
904 NSString* threadLabel = [
FlutterEngine generateThreadLabel:self.labelPrefix];
905 _threadHost = std::make_shared<flutter::ThreadHost>();
906 *_threadHost = MakeThreadHost(threadLabel, settings);
909 flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
910 [weakSelf](flutter::Shell& shell) {
913 return std::unique_ptr<flutter::PlatformViewIOS>();
915 [strongSelf recreatePlatformViewsController];
917 initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner()];
918 return std::make_unique<flutter::PlatformViewIOS>(
919 shell, strongSelf->_renderingApi, strongSelf.platformViewsController,
920 shell.GetTaskRunners(), shell.GetConcurrentWorkerTaskRunner(),
921 shell.GetIsGpuDisabledSyncSwitch());
924 flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
925 [](flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell); };
927 fml::RefPtr<fml::TaskRunner> ui_runner;
928 if (settings.enable_impeller &&
929 settings.merged_platform_ui_thread == flutter::Settings::MergedPlatformUIThread::kEnabled) {
930 ui_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
932 ui_runner = _threadHost->ui_thread->GetTaskRunner();
934 flutter::TaskRunners task_runners(threadLabel.UTF8String,
935 fml::MessageLoop::GetCurrent().GetTaskRunner(),
936 _threadHost->raster_thread->GetTaskRunner(),
938 _threadHost->io_thread->GetTaskRunner()
942 self.isGpuDisabled =
self.viewController
943 ?
self.viewController.stateIsBackground
946 UIApplicationStateBackground;
949 std::unique_ptr<flutter::Shell> shell = flutter::Shell::Create(
953 on_create_platform_view,
954 on_create_rasterizer,
957 if (shell ==
nullptr) {
958 NSString* errorMessage = [NSString
959 stringWithFormat:@"Could not start a shell FlutterEngine with entrypoint: %@", entrypoint];
960 [FlutterLogger logError:errorMessage];
962 [
self setUpShell:std::move(shell)
963 withVMServicePublication:settings.enable_vm_service_publication];
965 [
self startProfiler];
972 - (BOOL)performImplicitEngineCallback {
975 id<FlutterImplicitEngineDelegate> provider = (id<FlutterImplicitEngineDelegate>)appDelegate;
977 initWithEngine:self]];
983 - (void)updateDisplays {
988 auto vsync_waiter =
_shell->GetVsyncWaiter().lock();
989 auto vsync_waiter_ios = std::static_pointer_cast<flutter::VsyncWaiterIOS>(vsync_waiter);
990 std::vector<std::unique_ptr<flutter::Display>> displays;
991 auto screen_size = UIScreen.mainScreen.nativeBounds.size;
992 auto scale = UIScreen.mainScreen.scale;
993 displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(
994 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale));
995 _shell->OnDisplayUpdates(std::move(displays));
999 return [
self runWithEntrypoint:FlutterDefaultDartEntrypoint
1001 initialRoute:FlutterDefaultInitialRoute];
1004 - (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
1005 return [
self runWithEntrypoint:entrypoint
1006 libraryURI:libraryURI
1007 initialRoute:FlutterDefaultInitialRoute];
1010 - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
1011 return [
self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
1014 - (BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
1015 return [
self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
1018 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
1019 libraryURI:(NSString*)libraryURI
1020 initialRoute:(NSString*)initialRoute {
1021 return [
self runWithEntrypoint:entrypoint
1022 libraryURI:libraryURI
1023 initialRoute:initialRoute
1024 entrypointArgs:nil];
1027 - (BOOL)runWithEntrypoint:(NSString*)entrypoint
1028 libraryURI:(NSString*)libraryURI
1029 initialRoute:(NSString*)initialRoute
1030 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
1031 if ([
self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
1032 [
self launchEngine:entrypoint libraryURI:libraryURI entrypointArgs:entrypointArgs];
1035 return _shell !=
nullptr;
1038 - (void)notifyLowMemory {
1040 _shell->NotifyLowMemoryWarning();
1042 [
self.systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
1045 #pragma mark - Text input delegate
1048 updateEditingClient:(
int)client
1049 withState:(NSDictionary*)state {
1050 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingState"
1051 arguments:@[ @(client), state ]];
1055 updateEditingClient:(
int)client
1056 withState:(NSDictionary*)state
1057 withTag:(NSString*)tag {
1058 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithTag"
1059 arguments:@[ @(client), @{tag : state} ]];
1063 updateEditingClient:(
int)client
1064 withDelta:(NSDictionary*)delta {
1065 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
1066 arguments:@[ @(client), delta ]];
1070 updateFloatingCursor:(FlutterFloatingCursorDragState)state
1071 withClient:(
int)client
1072 withPosition:(NSDictionary*)position {
1073 NSString* stateString;
1075 case FlutterFloatingCursorDragStateStart:
1076 stateString =
@"FloatingCursorDragState.start";
1078 case FlutterFloatingCursorDragStateUpdate:
1079 stateString =
@"FloatingCursorDragState.update";
1081 case FlutterFloatingCursorDragStateEnd:
1082 stateString =
@"FloatingCursorDragState.end";
1085 [
self.textInputChannel invokeMethod:@"TextInputClient.updateFloatingCursor"
1086 arguments:@[ @(client), stateString, position ]];
1090 performAction:(FlutterTextInputAction)action
1091 withClient:(
int)client {
1092 NSString* actionString;
1094 case FlutterTextInputActionUnspecified:
1099 actionString =
@"TextInputAction.unspecified";
1101 case FlutterTextInputActionDone:
1102 actionString =
@"TextInputAction.done";
1104 case FlutterTextInputActionGo:
1105 actionString =
@"TextInputAction.go";
1107 case FlutterTextInputActionSend:
1108 actionString =
@"TextInputAction.send";
1110 case FlutterTextInputActionSearch:
1111 actionString =
@"TextInputAction.search";
1113 case FlutterTextInputActionNext:
1114 actionString =
@"TextInputAction.next";
1116 case FlutterTextInputActionContinue:
1117 actionString =
@"TextInputAction.continueAction";
1119 case FlutterTextInputActionJoin:
1120 actionString =
@"TextInputAction.join";
1122 case FlutterTextInputActionRoute:
1123 actionString =
@"TextInputAction.route";
1125 case FlutterTextInputActionEmergencyCall:
1126 actionString =
@"TextInputAction.emergencyCall";
1128 case FlutterTextInputActionNewline:
1129 actionString =
@"TextInputAction.newline";
1132 [
self.textInputChannel invokeMethod:@"TextInputClient.performAction"
1133 arguments:@[ @(client), actionString ]];
1137 showAutocorrectionPromptRectForStart:(NSUInteger)start
1139 withClient:(
int)client {
1140 [
self.textInputChannel invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
1141 arguments:@[ @(client), @(start), @(end) ]];
1145 willDismissEditMenuWithTextInputClient:(
int)client {
1146 [
self.platformChannel invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
1147 arguments:@[ @(client) ]];
1151 shareSelectedText:(NSString*)selectedText {
1152 [
self.platformPlugin showShareViewController:selectedText];
1156 searchWebWithSelectedText:(NSString*)selectedText {
1157 [
self.platformPlugin searchWeb:selectedText];
1161 lookUpSelectedText:(NSString*)selectedText {
1162 [
self.platformPlugin showLookUpViewController:selectedText];
1166 performContextMenuCustomActionWithActionID:(NSString*)actionID
1167 textInputClient:(
int)client {
1168 [
self.platformChannel invokeMethod:@"ContextMenu.onPerformCustomAction"
1169 arguments:@[ @(client), actionID ]];
1172 #pragma mark - FlutterViewEngineDelegate
1178 [
self.textInputChannel invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
1182 focusElement:(UIScribbleElementIdentifier)elementIdentifier
1183 atPoint:(CGPoint)referencePoint
1188 [
self.textInputChannel
1189 invokeMethod:@"TextInputClient.focusElement"
1190 arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
1195 requestElementsInRect:(CGRect)rect
1200 [
self.textInputChannel
1201 invokeMethod:@"TextInputClient.requestElementsInRect"
1202 arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
1210 [
self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
1217 [
self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionFinished" arguments:nil];
1221 insertTextPlaceholderWithSize:(CGSize)size
1222 withClient:(
int)client {
1226 [
self.textInputChannel invokeMethod:@"TextInputClient.insertTextPlaceholder"
1227 arguments:@[ @(client), @(size.width), @(size.height) ]];
1231 removeTextPlaceholder:(
int)client {
1235 [
self.textInputChannel invokeMethod:@"TextInputClient.removeTextPlaceholder"
1236 arguments:@[ @(client) ]];
1240 didResignFirstResponderWithTextInputClient:(
int)client {
1244 [
self.textInputChannel invokeMethod:@"TextInputClient.onConnectionClosed"
1245 arguments:@[ @(client) ]];
1266 dispatch_async(dispatch_get_main_queue(), ^(
void) {
1267 long platform_view_id = [
self.platformViewsController firstResponderPlatformViewId];
1268 if (platform_view_id == -1) {
1272 [
self.platformViewsChannel invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
1276 #pragma mark - Undo Manager Delegate
1278 - (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
1279 NSString* action = (direction == FlutterUndoRedoDirectionUndo) ?
@"undo" :
@"redo";
1280 [
self.undoManagerChannel invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
1283 - (UIView<UITextInput>*)activeTextInputView {
1284 return [[
self textInputPlugin] textInputView];
1287 - (NSUndoManager*)undoManager {
1288 return self.viewController.undoManager;
1291 #pragma mark - Screenshot Delegate
1293 - (
flutter::Rasterizer::Screenshot)takeScreenshot:(
flutter::Rasterizer::ScreenshotType)type
1294 asBase64Encoded:(BOOL)base64Encode {
1295 FML_DCHECK(
_shell) <<
"Cannot takeScreenshot without a shell";
1296 return _shell->Screenshot(type, base64Encode);
1299 - (void)flutterViewAccessibilityDidCall {
1301 [
self ensureSemanticsEnabled];
1323 #pragma mark - FlutterBinaryMessenger
1325 - (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
1326 [
self sendOnChannel:channel message:message binaryReply:nil];
1329 - (void)sendOnChannel:(NSString*)channel
1330 message:(NSData*)message
1332 NSParameterAssert(channel);
1334 @"Sending a message before the FlutterEngine has been run.");
1335 fml::RefPtr<flutter::PlatformMessageResponseDarwin> response =
1336 (callback == nil) ?
nullptr
1337 : fml::MakeRefCounted<flutter::PlatformMessageResponseDarwin>(
1341 _shell->GetTaskRunners().GetPlatformTaskRunner());
1342 std::unique_ptr<flutter::PlatformMessage> platformMessage =
1343 (message == nil) ? std::make_unique<flutter::PlatformMessage>(channel.UTF8String, response)
1344 : std::make_unique<flutter::PlatformMessage>(
1347 _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
1357 binaryMessageHandler:
1359 return [
self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
1363 setMessageHandlerOnChannel:(NSString*)channel
1366 NSParameterAssert(channel);
1368 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
1369 handler, taskQueue);
1370 return [
self.connections acquireConnectionForChannel:channel];
1372 NSAssert(!handler,
@"Setting a message handler before the FlutterEngine has been run.");
1374 return [FlutterConnectionCollection makeErrorConnectionWithErrorCode:-1L];
1380 NSString* channel = [
self.connections cleanupConnectionWithID:connection];
1381 if (channel.length > 0) {
1382 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String, nil,
1388 #pragma mark - FlutterTextureRegistry
1391 FML_DCHECK(
self.platformView);
1392 int64_t textureId =
self.nextTextureId++;
1393 self.platformView->RegisterExternalTexture(textureId, texture);
1397 - (void)unregisterTexture:(int64_t)textureId {
1398 _shell->GetPlatformView()->UnregisterTexture(textureId);
1401 - (void)textureFrameAvailable:(int64_t)textureId {
1402 _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
1405 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1409 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1413 - (id<FlutterPluginRegistry>)pluginRegistry {
1417 #pragma mark - FlutterPluginRegistry
1420 NSAssert(
self.pluginPublications[pluginKey] == nil,
@"Duplicate plugin key: %@", pluginKey);
1421 self.pluginPublications[pluginKey] = [NSNull null];
1423 flutterEngine:self];
1424 self.registrars[pluginKey] = result;
1429 NSAssert(
self.pluginPublications[key] == nil,
@"Duplicate key: %@", key);
1430 self.pluginPublications[key] = [NSNull null];
1433 self.registrars[key] = result;
1437 - (BOOL)hasPlugin:(NSString*)pluginKey {
1438 return _pluginPublications[pluginKey] != nil;
1441 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1442 return _pluginPublications[pluginKey];
1446 [
self.sceneLifeCycleDelegate addDelegate:delegate];
1449 #pragma mark - Notifications
1451 - (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1455 [
self flutterWillEnterForeground:notification];
1458 - (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1462 [
self flutterDidEnterBackground:notification];
1465 - (void)applicationWillEnterForeground:(NSNotification*)notification {
1466 [
self flutterWillEnterForeground:notification];
1469 - (void)applicationDidEnterBackground:(NSNotification*)notification {
1470 [
self flutterDidEnterBackground:notification];
1473 - (void)flutterWillEnterForeground:(NSNotification*)notification {
1474 [
self setIsGpuDisabled:NO];
1477 - (void)flutterDidEnterBackground:(NSNotification*)notification {
1478 [
self setIsGpuDisabled:YES];
1479 [
self notifyLowMemory];
1482 - (void)onMemoryWarning:(NSNotification*)notification {
1483 [
self notifyLowMemory];
1486 - (void)setIsGpuDisabled:(BOOL)value {
1488 _shell->SetGpuAvailability(value ? flutter::GpuAvailability::kUnavailable
1489 : flutter::GpuAvailability::kAvailable);
1491 _isGpuDisabled = value;
1494 #pragma mark - Locale updates
1496 - (void)onLocaleUpdated:(NSNotification*)notification {
1498 NSMutableArray<NSString*>* localeData = [[NSMutableArray alloc] init];
1499 NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
1500 for (NSString* localeID in preferredLocales) {
1501 NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
1502 NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
1503 NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
1504 NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
1505 NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
1506 if (!languageCode) {
1509 [localeData addObject:languageCode];
1510 [localeData addObject:(countryCode ? countryCode : @"")];
1511 [localeData addObject:(scriptCode ? scriptCode : @"")];
1512 [localeData addObject:(variantCode ? variantCode : @"")];
1514 if (localeData.count == 0) {
1517 [
self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
1520 - (void)onStatusBarTap {
1524 [
self.statusBarChannel invokeMethod:@"handleScrollToTop" arguments:nil];
1527 - (void)waitForFirstFrameSync:(NSTimeInterval)timeout
1528 callback:(NS_NOESCAPE
void (^_Nonnull)(BOOL didTimeout))callback {
1529 fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
1530 fml::Status status =
self.shell.WaitForFirstFrame(waitTime);
1531 callback(status.code() == fml::StatusCode::kDeadlineExceeded);
1534 - (void)waitForFirstFrame:(NSTimeInterval)timeout
1535 callback:(
void (^_Nonnull)(BOOL didTimeout))callback {
1536 dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
1537 dispatch_group_t group = dispatch_group_create();
1540 __block BOOL didTimeout = NO;
1541 dispatch_group_async(group, queue, ^{
1547 fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
1548 fml::Status status = strongSelf.
shell.WaitForFirstFrame(waitTime);
1549 didTimeout = status.code() == fml::StatusCode::kDeadlineExceeded;
1553 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
1567 callback(didTimeout);
1571 - (
FlutterEngine*)spawnWithEntrypoint:( NSString*)entrypoint
1572 libraryURI:( NSString*)libraryURI
1573 initialRoute:( NSString*)initialRoute
1574 entrypointArgs:( NSArray<NSString*>*)entrypointArgs {
1575 NSAssert(
_shell,
@"Spawning from an engine without a shell (possibly not run).");
1577 project:self.dartProject
1578 allowHeadlessExecution:self.allowHeadlessExecution];
1579 flutter::RunConfiguration configuration =
1580 [
self.dartProject runConfigurationForEntrypoint:entrypoint
1581 libraryOrNil:libraryURI
1582 entrypointArgs:entrypointArgs];
1584 configuration.SetEngineId(result.engineIdentifier);
1591 std::shared_ptr<flutter::IOSContext> context = ios_platform_view->
GetIosContext();
1592 FML_DCHECK(context);
1596 flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
1597 [result, context](flutter::Shell& shell) {
1598 [result recreatePlatformViewsController];
1600 initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner()];
1601 return std::make_unique<flutter::PlatformViewIOS>(
1602 shell, context, result.platformViewsController, shell.GetTaskRunners());
1605 flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
1606 [](flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell); };
1608 std::string cppInitialRoute;
1610 cppInitialRoute = [initialRoute UTF8String];
1613 std::unique_ptr<flutter::Shell> shell =
_shell->Spawn(
1614 std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1616 result->_threadHost = _threadHost;
1618 result->_isGpuDisabled = _isGpuDisabled;
1619 [result setUpShell:std::move(shell) withVMServicePublication:NO];
1623 - (const
flutter::ThreadHost&)threadHost {
1624 return *_threadHost;
1628 return self.dartProject;
1631 - (void)sendDeepLinkToFramework:(NSURL*)url completionHandler:(
void (^)(BOOL success))completion {
1633 [
self waitForFirstFrame:3.0
1634 callback:^(BOOL didTimeout) {
1637 logError:@"Timeout waiting for first frame when launching a URL."];
1641 [weakSelf.navigationChannel
1642 invokeMethod:@"pushRouteInformation"
1644 @"location" : url.absoluteString ?: [NSNull null],
1646 result:^(id _Nullable result) {
1648 [result isKindOfClass:[NSNumber class]] && [result boolValue];
1652 logError:@"Failed to handle route information in Flutter."];
1654 completion(success);
1664 - (instancetype)initWithKey:(NSString*)key flutterEngine:(
FlutterEngine*)flutterEngine {
1665 self = [
super init];
1666 NSAssert(
self,
@"Super init cannot be nil");
1673 return _flutterEngine.binaryMessenger;
1676 return _flutterEngine.textureRegistry;
1680 withId:(NSString*)factoryId {
1681 [
self registerViewFactory:factory
1683 gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
1687 withId:(NSString*)factoryId
1688 gestureRecognizersBlockingPolicy:
1690 [_flutterEngine.platformViewsController registerViewFactory:factory
1692 gestureRecognizersBlockingPolicy:gestureRecognizersBlockingPolicy];
1700 return self.flutterEngine.viewController;
1703 - (void)publish:(NSObject*)value {
1704 self.flutterEngine.pluginPublications[
self.key] = value;
1707 - (void)addMethodCallDelegate:(NSObject<
FlutterPlugin>*)delegate
1717 static BOOL FLTFlutterPluginRespondsToLegacyAppLifecycleSelectors(
1718 NSObject<FlutterPlugin>* delegate) {
1720 @selector(applicationDidBecomeActive:),
1721 @selector(applicationWillResignActive:),
1722 @selector(applicationWillEnterForeground:),
1723 @selector(applicationDidEnterBackground:),
1724 @selector(application:continueUserActivity:restorationHandler:),
1725 @selector(application:performActionForShortcutItem:completionHandler:),
1726 @selector(application:openURL:options:),
1727 @selector(application:performFetchWithCompletionHandler:),
1729 for (
SEL sel : selectors) {
1730 if ([delegate respondsToSelector:sel]) {
1737 - (void)addApplicationDelegate:(NSObject<
FlutterPlugin>*)delegate {
1740 id<FlutterAppLifeCycleProvider> lifeCycleProvider =
1741 (id<FlutterAppLifeCycleProvider>)appDelegate;
1742 [lifeCycleProvider addApplicationLifeCycleDelegate:delegate];
1745 FLTFlutterPluginRespondsToLegacyAppLifecycleSelectors(delegate)) {
1748 [NSString stringWithFormat:
1749 @"Plugin %@ uses deprecated application lifecycle events. Please contact "
1750 @"plugin maintainers and request UIScene lifecycle support. This will be "
1751 @"required in a future version of Flutter. See "
1752 @"https://docs.flutter.dev/release/breaking-changes/"
1753 @"uiscenedelegate#migration-guide-for-flutter-plugins",
1760 [
self.flutterEngine addSceneLifeCycleDelegate:delegate];
1763 - (NSString*)lookupKeyForAsset:(NSString*)asset {
1764 return [
self.flutterEngine lookupKeyForAsset:asset];
1767 - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1768 return [
self.flutterEngine lookupKeyForAsset:asset fromPackage:package];
1771 - (nullable NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1772 return [
self.flutterEngine valuePublishedByPlugin:pluginKey];
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
FlutterFMLTaskRunner * _uiTaskRunnerWrapper
NSString *const FlutterDefaultDartEntrypoint
std::shared_ptr< flutter::SamplingProfiler > _profiler
std::unique_ptr< flutter::Shell > _shell
NSObject< FlutterApplicationRegistrar > * _appRegistrar
NSString *const kFlutterKeyDataChannel
NSString *const FlutterDefaultInitialRoute
FlutterFMLTaskRunner * _rasterTaskRunnerWrapper
flutter::IOSRenderingAPI _renderingApi
FlutterTextureRegistryRelay * _textureRegistry
static FLUTTER_ASSERT_ARC void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig &config)
static constexpr int kNumProfilerSamplesPerSec
FlutterFMLTaskRunner * _platformTaskRunnerWrapper
NSString *const kFlutterApplicationRegistrarKey
FlutterBinaryMessengerRelay * _binaryMessenger
FlutterPlatformViewGestureRecognizersBlockingPolicy
FlutterViewController * viewController
FlutterTextInputPlugin * textInputPlugin
FlutterRestorationPlugin * restorationPlugin
NSMutableDictionary * pluginPublications
FlutterEngineProcTable & embedderAPI
NSString * lookupKeyForAsset:fromPackage:(NSString *asset,[fromPackage] NSString *package)
const flutter::Settings & settings()
NSString * lookupKeyForAsset:(NSString *asset)
NSObject< FlutterBinaryMessenger > * parent
FlutterEngine * flutterEngine
FlutterMethodChannel * textInputChannel
flutter::PlatformViewIOS * platformView()
FlutterMethodChannel * navigationChannel
FlutterBasicMessageChannel * keyEventChannel
nullable FlutterFMLTaskRunner * platformTaskRunner()
FlutterBasicMessageChannel * lifecycleChannel
FlutterMethodChannel * platformChannel
FlutterMethodChannel * localizationChannel
FlutterBasicMessageChannel * systemChannel
FlutterBasicMessageChannel * settingsChannel
FlutterMethodChannel * restorationChannel
nullable FlutterFMLTaskRunner * rasterTaskRunner()
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
void setMethodCallHandler:(FlutterMethodCallHandler _Nullable handler)
UIApplication * application
NSObject< FlutterTextureRegistry > * parent
fml::MallocMapping CopyNSDataToMapping(NSData *data)
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
NSObject< FlutterTextureRegistry > * textures()
NSObject< FlutterBinaryMessenger > * messenger()
instancetype sharedInstance()
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)