diff --git a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index 41793e0c67..19d2486a69 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -22,7 +22,6 @@ _flutter_framework_headers = [ "framework/Headers/FlutterMacros.h", "framework/Headers/FlutterNavigationController.h", "framework/Headers/FlutterPlugin.h", - "framework/Headers/FlutterPluginAppLifeCycleDelegate.h", "framework/Headers/FlutterTexture.h", "framework/Headers/FlutterViewController.h", ] @@ -44,7 +43,6 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/FlutterNavigationController.mm", "framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.mm", - "framework/Source/FlutterPluginAppLifeCycleDelegate.mm", "framework/Source/FlutterStandardCodec.mm", "framework/Source/FlutterStandardCodec_Internal.h", "framework/Source/FlutterTextInputDelegate.h", diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h index d850854f2f..939040c8e5 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h @@ -43,7 +43,6 @@ #include "FlutterMacros.h" #include "FlutterNavigationController.h" #include "FlutterPlugin.h" -#include "FlutterPluginAppLifeCycleDelegate.h" #include "FlutterTexture.h" #include "FlutterViewController.h" diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h index f175ea2925..4f28e70b65 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h @@ -24,10 +24,22 @@ * code as necessary from FlutterAppDelegate.mm. */ FLUTTER_EXPORT -@interface FlutterAppDelegate : UIResponder +@interface FlutterAppDelegate : UIResponder @property(strong, nonatomic) UIWindow* window; +// Can be overriden by subclasses to provide a custom FlutterBinaryMessenger, +// typically a FlutterViewController, for plugin interop. +// +// Defaults to window's rootViewController. +- (NSObject*)binaryMessenger; + +// Can be overriden by subclasses to provide a custom FlutterTextureRegistry, +// typically a FlutterViewController, for plugin interop. +// +// Defaults to window's rootViewController. +- (NSObject*)textures; + @end #endif // FLUTTER_FLUTTERDARTPROJECT_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h index 46bee66f99..646ffa30d7 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h @@ -253,14 +253,6 @@ NS_ASSUME_NONNULL_BEGIN - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey; @end -/** - Implement this in the `UIAppDelegate` of your app to enable Flutter plugins to register themselves to the application - life cycle events. -*/ -@protocol FlutterAppLifeCycleProvider -- (void)addApplicationLifeCycleDelegate:(NSObject*)delegate; -@end - NS_ASSUME_NONNULL_END; #endif // FLUTTER_FLUTTERPLUGIN_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h deleted file mode 100644 index 676ef6f476..0000000000 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ -#define FLUTTER_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ - -#include "FlutterPlugin.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - Propagates `UIAppDelegate` callbacks to registered plugins. -*/ -FLUTTER_EXPORT -@interface FlutterPluginAppLifeCycleDelegate : NSObject -/** - Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifecycleDelegate as long as it is alive. - - `delegate` will only referenced weakly. -*/ -- (void)addDelegate:(NSObject*)delegate; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - - - Returns: `NO` if any plugin vetoes application launch. - */ -- (BOOL)application:(UIApplication*)application - didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)applicationDidBecomeActive:(UIApplication*)application; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)applicationWillResignActive:(UIApplication*)application; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)applicationDidEnterBackground:(UIApplication*)application; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)applicationWillEnterForeground:(UIApplication*)application; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)applicationWillTerminate:(UIApplication*)application; - -/** - Called if this plugin has been registered for `UIApplicationDelegate` callbacks. - */ -- (void)application:(UIApplication*)application - didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)application:(UIApplication*)application - didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. - */ -- (void)application:(UIApplication*)application - didReceiveRemoteNotification:(NSDictionary*)userInfo - fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles - the request. - - - Returns: `YES` if any plugin handles the request. -*/ -- (BOOL)application:(UIApplication*)application - openURL:(NSURL*)url - options:(NSDictionary*)options; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles - the request. - - - Returns: `YES` if any plugin handles the request. - */ -- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles - the request. - - - Returns: `YES` if any plugin handles the request. -*/ -- (BOOL)application:(UIApplication*)application - openURL:(NSURL*)url - sourceApplication:(NSString*)sourceApplication - annotation:(id)annotation; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks. -*/ -- (void)application:(UIApplication*)application - performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem - completionHandler:(void (^)(BOOL succeeded))completionHandler - API_AVAILABLE(ios(9.0)); - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles - the request. - - - Returns: `YES` if any plugin handles the request. -*/ -- (BOOL)application:(UIApplication*)application - handleEventsForBackgroundURLSession:(nonnull NSString*)identifier - completionHandler:(nonnull void (^)())completionHandler; - -/** - Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles - the request. - - - Returns: `YES` if any plugin handles the request. -*/ -- (BOOL)application:(UIApplication*)application - performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; -@end - -NS_ASSUME_NONNULL_END - -#endif // FLUTTER_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ \ No newline at end of file diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h index 524890ca2c..7ef6868a27 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h @@ -11,11 +11,10 @@ #include "FlutterBinaryMessenger.h" #include "FlutterDartProject.h" #include "FlutterMacros.h" -#include "FlutterPlugin.h" #include "FlutterTexture.h" FLUTTER_EXPORT -@interface FlutterViewController : UIViewController +@interface FlutterViewController : UIViewController - (instancetype)initWithProject:(FlutterDartProject*)project nibName:(NSString*)nibNameOrNil @@ -50,8 +49,6 @@ FLUTTER_EXPORT */ - (void)setInitialRoute:(NSString*)route; -- (id)pluginRegistry; - @end #endif // FLUTTER_FLUTTERVIEWCONTROLLER_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm index b175966f3d..a5132bf4ee 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm @@ -3,28 +3,46 @@ // found in the LICENSE file. #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#include "lib/fxl/logging.h" + +@interface FlutterAppDelegate () +@property(readonly, nonatomic) NSMutableArray* pluginDelegates; +@property(readonly, nonatomic) NSMutableDictionary* pluginPublications; +@end + +@interface FlutterAppDelegateRegistrar : NSObject +- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(FlutterAppDelegate*)delegate; +@end @implementation FlutterAppDelegate { - FlutterPluginAppLifeCycleDelegate* _lifeCycleDelegate; + UIBackgroundTaskIdentifier _debugBackgroundTask; } - (instancetype)init { if (self = [super init]) { - _lifeCycleDelegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; + _pluginDelegates = [NSMutableArray new]; + _pluginPublications = [NSMutableDictionary new]; } return self; } - (void)dealloc { - [_lifeCycleDelegate release]; + [_pluginDelegates release]; + [_pluginPublications release]; [super dealloc]; } - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if (![plugin application:application didFinishLaunchingWithOptions:launchOptions]) { + return NO; + } + } + } + return YES; } // Returns the key window's rootViewController, if it's a FlutterViewController. @@ -47,118 +65,257 @@ } - (void)applicationDidEnterBackground:(UIApplication*)application { - [_lifeCycleDelegate applicationDidEnterBackground:application]; +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + // The following keeps the Flutter session alive when the device screen locks + // in debug mode. It allows continued use of features like hot reload and + // taking screenshots once the device unlocks again. + // + // Note the name is not an identifier and multiple instances can exist. + _debugBackgroundTask = [application + beginBackgroundTaskWithName:@"Flutter debug task" + expirationHandler:^{ + FXL_LOG(WARNING) + << "\nThe OS has terminated the Flutter debug connection for being " + "inactive in the background for too long.\n\n" + "There are no errors with your Flutter application.\n\n" + "To reconnect, launch your application again via 'flutter run'"; + }]; +#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin applicationDidEnterBackground:application]; + } + } } - (void)applicationWillEnterForeground:(UIApplication*)application { - [_lifeCycleDelegate applicationWillEnterForeground:application]; +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + [application endBackgroundTask:_debugBackgroundTask]; +#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin applicationWillEnterForeground:application]; + } + } } - (void)applicationWillResignActive:(UIApplication*)application { - [_lifeCycleDelegate applicationWillResignActive:application]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin applicationWillResignActive:application]; + } + } } - (void)applicationDidBecomeActive:(UIApplication*)application { - [_lifeCycleDelegate applicationDidBecomeActive:application]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin applicationDidBecomeActive:application]; + } + } } - (void)applicationWillTerminate:(UIApplication*)application { - [_lifeCycleDelegate applicationWillTerminate:application]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin applicationWillTerminate:application]; + } + } } - (void)application:(UIApplication*)application didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings { - [_lifeCycleDelegate application:application - didRegisterUserNotificationSettings:notificationSettings]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin application:application didRegisterUserNotificationSettings:notificationSettings]; + } + } } - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { - [_lifeCycleDelegate application:application - didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + [plugin application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; + } + } } - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - [_lifeCycleDelegate application:application - didReceiveRemoteNotification:userInfo - fetchCompletionHandler:completionHandler]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application + didReceiveRemoteNotification:userInfo + fetchCompletionHandler:completionHandler]) { + return; + } + } + } } - (BOOL)application:(UIApplication*)application openURL:(NSURL*)url options:(NSDictionary*)options { - return [_lifeCycleDelegate application:application openURL:url options:options]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application openURL:url options:options]) { + return YES; + } + } + } + return NO; } - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url { - return [_lifeCycleDelegate application:application handleOpenURL:url]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application handleOpenURL:url]) { + return YES; + } + } + } + return NO; } - (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { - return [_lifeCycleDelegate application:application - openURL:url - sourceApplication:sourceApplication - annotation:annotation]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]) { + return YES; + } + } + } + return NO; } - (void)application:(UIApplication*)application performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler NS_AVAILABLE_IOS(9_0) { - [_lifeCycleDelegate application:application - performActionForShortcutItem:shortcutItem - completionHandler:completionHandler]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application + performActionForShortcutItem:shortcutItem + completionHandler:completionHandler]) { + return; + } + } + } } - (void)application:(UIApplication*)application handleEventsForBackgroundURLSession:(nonnull NSString*)identifier completionHandler:(nonnull void (^)())completionHandler { - [_lifeCycleDelegate application:application - handleEventsForBackgroundURLSession:identifier - completionHandler:completionHandler]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application + handleEventsForBackgroundURLSession:identifier + completionHandler:completionHandler]) { + return; + } + } + } } - (void)application:(UIApplication*)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - [_lifeCycleDelegate application:application performFetchWithCompletionHandler:completionHandler]; + for (id plugin in _pluginDelegates) { + if ([plugin respondsToSelector:_cmd]) { + if ([plugin application:application performFetchWithCompletionHandler:completionHandler]) { + return; + } + } + } } -#pragma mark - FlutterPluginRegistry methods. All delegating to the rootViewController - -- (NSObject*)registrarForPlugin:(NSString*)pluginKey { +// TODO(xster): move when doing https://github.com/flutter/flutter/issues/3671. +- (NSObject*)binaryMessenger { UIViewController* rootViewController = _window.rootViewController; - if ([rootViewController isKindOfClass:[FlutterViewController class]]) { - return - [[(FlutterViewController*)rootViewController pluginRegistry] registrarForPlugin:pluginKey]; + if ([rootViewController conformsToProtocol:@protocol(FlutterBinaryMessenger)]) { + return (NSObject*)rootViewController; } return nil; } +- (NSObject*)textures { + UIViewController* rootViewController = _window.rootViewController; + if ([rootViewController conformsToProtocol:@protocol(FlutterTextureRegistry)]) { + return (NSObject*)rootViewController; + } + return nil; +} + +- (NSObject*)registrarForPlugin:(NSString*)pluginKey { + NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey); + self.pluginPublications[pluginKey] = [NSNull null]; + return + [[[FlutterAppDelegateRegistrar alloc] initWithPlugin:pluginKey appDelegate:self] autorelease]; +} + - (BOOL)hasPlugin:(NSString*)pluginKey { - UIViewController* rootViewController = _window.rootViewController; - if ([rootViewController isKindOfClass:[FlutterViewController class]]) { - return [[(FlutterViewController*)rootViewController pluginRegistry] hasPlugin:pluginKey]; - } - return nil; + return _pluginPublications[pluginKey] != nil; } - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey { - UIViewController* rootViewController = _window.rootViewController; - if ([rootViewController isKindOfClass:[FlutterViewController class]]) { - return [[(FlutterViewController*)rootViewController pluginRegistry] - valuePublishedByPlugin:pluginKey]; - } - return nil; + return _pluginPublications[pluginKey]; +} +@end + +@implementation FlutterAppDelegateRegistrar { + NSString* _pluginKey; + FlutterAppDelegate* _appDelegate; } -#pragma mark - FlutterAppLifeCycleProvider methods +- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(FlutterAppDelegate*)appDelegate { + self = [super init]; + NSAssert(self, @"Super init cannot be nil"); + _pluginKey = [pluginKey retain]; + _appDelegate = [appDelegate retain]; + return self; +} -- (void)addApplicationLifeCycleDelegate:(NSObject*)delegate { - [_lifeCycleDelegate addDelegate:delegate]; +- (void)dealloc { + [_pluginKey release]; + [_appDelegate release]; + [super dealloc]; +} + +- (NSObject*)messenger { + return [_appDelegate binaryMessenger]; +} + +- (NSObject*)textures { + return [_appDelegate textures]; +} + +- (void)publish:(NSObject*)value { + _appDelegate.pluginPublications[_pluginKey] = value; +} + +- (void)addMethodCallDelegate:(NSObject*)delegate + channel:(FlutterMethodChannel*)channel { + [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { + [delegate handleMethodCall:call result:result]; + }]; +} + +- (void)addApplicationDelegate:(NSObject*)delegate { + [_appDelegate.pluginDelegates addObject:delegate]; +} + +- (NSString*)lookupKeyForAsset:(NSString*)asset { + return [FlutterDartProject lookupKeyForAsset:asset]; +} + +- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { + return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package]; } @end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm deleted file mode 100644 index 900d048c57..0000000000 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" -#include "lib/fxl/logging.h" - -@implementation FlutterPluginAppLifeCycleDelegate { - UIBackgroundTaskIdentifier _debugBackgroundTask; - - // Weak references to registered plugins. - NSPointerArray* _pluginDelegates; -} - -- (instancetype)init { - if (self = [super init]) { - _pluginDelegates = [[NSPointerArray weakObjectsPointerArray] retain]; - } - return self; -} - -- (void)dealloc { - [_pluginDelegates release]; - [super dealloc]; -} - -static BOOL isPowerOfTwo(NSUInteger x) { - return x != 0 && (x & (x - 1)) == 0; -} - -- (void)addDelegate:(NSObject*)delegate { - [_pluginDelegates addPointer:(__bridge void*)delegate]; - if (isPowerOfTwo([_pluginDelegates count])) { - [_pluginDelegates compact]; - } -} - -- (BOOL)application:(UIApplication*)application - didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - for (id plugin in [_pluginDelegates allObjects]) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if (![plugin application:application didFinishLaunchingWithOptions:launchOptions]) { - return NO; - } - } - } - return YES; -} - -// Returns the key window's rootViewController, if it's a FlutterViewController. -// Otherwise, returns nil. -- (FlutterViewController*)rootFlutterViewController { - UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController; - if ([viewController isKindOfClass:[FlutterViewController class]]) { - return (FlutterViewController*)viewController; - } - return nil; -} - -- (void)applicationDidEnterBackground:(UIApplication*)application { -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - // The following keeps the Flutter session alive when the device screen locks - // in debug mode. It allows continued use of features like hot reload and - // taking screenshots once the device unlocks again. - // - // Note the name is not an identifier and multiple instances can exist. - _debugBackgroundTask = [application - beginBackgroundTaskWithName:@"Flutter debug task" - expirationHandler:^{ - FXL_LOG(WARNING) - << "\nThe OS has terminated the Flutter debug connection for being " - "inactive in the background for too long.\n\n" - "There are no errors with your Flutter application.\n\n" - "To reconnect, launch your application again via 'flutter run'"; - }]; -#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin applicationDidEnterBackground:application]; - } - } -} - -- (void)applicationWillEnterForeground:(UIApplication*)application { -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - [application endBackgroundTask:_debugBackgroundTask]; -#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin applicationWillEnterForeground:application]; - } - } -} - -- (void)applicationWillResignActive:(UIApplication*)application { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin applicationWillResignActive:application]; - } - } -} - -- (void)applicationDidBecomeActive:(UIApplication*)application { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin applicationDidBecomeActive:application]; - } - } -} - -- (void)applicationWillTerminate:(UIApplication*)application { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin applicationWillTerminate:application]; - } - } -} - -- (void)application:(UIApplication*)application - didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin application:application didRegisterUserNotificationSettings:notificationSettings]; - } - } -} - -- (void)application:(UIApplication*)application - didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - [plugin application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; - } - } -} - -- (void)application:(UIApplication*)application - didReceiveRemoteNotification:(NSDictionary*)userInfo - fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application - didReceiveRemoteNotification:userInfo - fetchCompletionHandler:completionHandler]) { - return; - } - } - } -} - -- (BOOL)application:(UIApplication*)application - openURL:(NSURL*)url - options:(NSDictionary*)options { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application openURL:url options:options]) { - return YES; - } - } - } - return NO; -} - -- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application handleOpenURL:url]) { - return YES; - } - } - } - return NO; -} - -- (BOOL)application:(UIApplication*)application - openURL:(NSURL*)url - sourceApplication:(NSString*)sourceApplication - annotation:(id)annotation { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application - openURL:url - sourceApplication:sourceApplication - annotation:annotation]) { - return YES; - } - } - } - return NO; -} - -- (void)application:(UIApplication*)application - performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem - completionHandler:(void (^)(BOOL succeeded))completionHandler NS_AVAILABLE_IOS(9_0) { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application - performActionForShortcutItem:shortcutItem - completionHandler:completionHandler]) { - return; - } - } - } -} - -- (BOOL)application:(UIApplication*)application - handleEventsForBackgroundURLSession:(nonnull NSString*)identifier - completionHandler:(nonnull void (^)())completionHandler { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application - handleEventsForBackgroundURLSession:identifier - completionHandler:completionHandler]) { - return YES; - } - } - } - return NO; -} - -- (BOOL)application:(UIApplication*)application - performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - for (id plugin in _pluginDelegates) { - if (!plugin) { - continue; - } - if ([plugin respondsToSelector:_cmd]) { - if ([plugin application:application performFetchWithCompletionHandler:completionHandler]) { - return YES; - } - } - } - return NO; -} -@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index e3076c6c05..2e13ffb738 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -22,12 +22,6 @@ #include "flutter/shell/platform/darwin/ios/platform_view_ios.h" @interface FlutterViewController () -@property(nonatomic, readonly) NSMutableDictionary* pluginPublications; -@end - -@interface FlutterViewControllerRegistrar : NSObject -- (instancetype)initWithPlugin:(NSString*)pluginKey - flutterViewController:(FlutterViewController*)flutterViewController; @end @implementation FlutterViewController { @@ -99,8 +93,6 @@ if ([self setupShell]) { [self setupChannels]; [self setupNotificationCenterObservers]; - - _pluginPublications = [NSMutableDictionary new]; } } @@ -434,7 +426,6 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; - [_pluginPublications release]; [super dealloc]; } @@ -980,82 +971,4 @@ constexpr CGFloat kStandardStatusBarHeight = 20.0; return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package]; } -- (id)pluginRegistry { - return self; -} - -#pragma mark - FlutterPluginRegistry - -- (NSObject*)registrarForPlugin:(NSString*)pluginKey { - NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey); - self.pluginPublications[pluginKey] = [NSNull null]; - return - [[FlutterViewControllerRegistrar alloc] initWithPlugin:pluginKey flutterViewController:self]; -} - -- (BOOL)hasPlugin:(NSString*)pluginKey { - return _pluginPublications[pluginKey] != nil; -} - -- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey { - return _pluginPublications[pluginKey]; -} -@end - -@implementation FlutterViewControllerRegistrar { - NSString* _pluginKey; - FlutterViewController* _flutterViewController; -} - -- (instancetype)initWithPlugin:(NSString*)pluginKey - flutterViewController:(FlutterViewController*)flutterViewController { - self = [super init]; - NSAssert(self, @"Super init cannot be nil"); - _pluginKey = [pluginKey retain]; - _flutterViewController = [flutterViewController retain]; - return self; -} - -- (void)dealloc { - [_pluginKey release]; - [_flutterViewController release]; - [super dealloc]; -} - -- (NSObject*)messenger { - return _flutterViewController; -} - -- (NSObject*)textures { - return _flutterViewController; -} - -- (void)publish:(NSObject*)value { - _flutterViewController.pluginPublications[_pluginKey] = value; -} - -- (void)addMethodCallDelegate:(NSObject*)delegate - channel:(FlutterMethodChannel*)channel { - [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { - [delegate handleMethodCall:call result:result]; - }]; -} - -- (void)addApplicationDelegate:(NSObject*)delegate { - id appDelegate = [[UIApplication sharedApplication] delegate]; - if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifeCycleProvider)]) { - id lifeCycleProvider = - (id)appDelegate; - [lifeCycleProvider addApplicationLifeCycleDelegate:delegate]; - } -} - -- (NSString*)lookupKeyForAsset:(NSString*)asset { - return [_flutterViewController lookupKeyForAsset:asset]; -} - -- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { - return [_flutterViewController lookupKeyForAsset:asset fromPackage:package]; -} - @end