7 #import "flutter/fml/logging.h"
29 - (instancetype)init {
30 if (
self = [super init]) {
36 - (BOOL)application:(UIApplication*)application
37 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
38 return [
self.lifeCycleDelegate application:application
39 willFinishLaunchingWithOptions:launchOptions];
42 - (BOOL)application:(UIApplication*)application
43 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
44 return [
self.lifeCycleDelegate application:application
45 didFinishLaunchingWithOptions:launchOptions];
51 if (_rootFlutterViewControllerGetter != nil) {
52 return _rootFlutterViewControllerGetter();
54 UIViewController* rootViewController = _window.rootViewController;
62 - (void)applicationDidEnterBackground:(UIApplication*)application {
66 - (void)applicationWillEnterForeground:(UIApplication*)application {
70 - (void)applicationWillResignActive:(UIApplication*)application {
74 - (void)applicationDidBecomeActive:(UIApplication*)application {
78 - (void)applicationWillTerminate:(UIApplication*)application {
81 #pragma GCC diagnostic push
82 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
83 - (void)application:(UIApplication*)application
84 didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
85 [
self.lifeCycleDelegate application:application
86 didRegisterUserNotificationSettings:notificationSettings];
88 #pragma GCC diagnostic pop
90 - (void)application:(UIApplication*)application
91 didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
92 [
self.lifeCycleDelegate application:application
93 didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
96 - (void)application:(UIApplication*)application
97 didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
98 [
self.lifeCycleDelegate application:application
99 didFailToRegisterForRemoteNotificationsWithError:error];
102 #pragma GCC diagnostic push
103 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
104 - (void)application:(UIApplication*)application
105 didReceiveLocalNotification:(UILocalNotification*)notification {
106 [
self.lifeCycleDelegate application:application didReceiveLocalNotification:notification];
108 #pragma GCC diagnostic pop
110 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
111 willPresentNotification:(UNNotification*)notification
112 withCompletionHandler:
113 (
void (^)(UNNotificationPresentationOptions options))completionHandler {
114 if ([
self.lifeCycleDelegate respondsToSelector:_cmd]) {
115 [
self.lifeCycleDelegate userNotificationCenter:center
116 willPresentNotification:notification
117 withCompletionHandler:completionHandler];
124 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
125 didReceiveNotificationResponse:(UNNotificationResponse*)response
126 withCompletionHandler:(
void (^)(
void))completionHandler {
127 if ([
self.lifeCycleDelegate respondsToSelector:_cmd]) {
128 [
self.lifeCycleDelegate userNotificationCenter:center
129 didReceiveNotificationResponse:response
130 withCompletionHandler:completionHandler];
134 - (BOOL)isFlutterDeepLinkingEnabled {
135 NSNumber* isDeepLinkingEnabled =
136 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"];
138 return isDeepLinkingEnabled ? [isDeepLinkingEnabled boolValue] : YES;
142 - (BOOL)application:(UIApplication*)application
144 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options {
145 if ([
self.lifeCycleDelegate application:application openURL:url options:options]) {
150 return [
self handleOpenURL:url options:options relayToSystemIfUnhandled:NO];
154 - (BOOL)handleOpenURL:(NSURL*)url
155 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options
156 relayToSystemIfUnhandled:(BOOL)throwBack {
157 if (![
self isFlutterDeepLinkingEnabled]) {
162 if (flutterViewController) {
163 [flutterViewController sendDeepLinkToFramework:url
164 completionHandler:^(BOOL success) {
165 if (!success && throwBack) {
167 [UIApplication.sharedApplication openURL:url];
171 FML_LOG(ERROR) <<
"Attempting to open an URL without a Flutter RootViewController.";
177 - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
178 return [
self.lifeCycleDelegate application:application handleOpenURL:url];
181 - (BOOL)application:(UIApplication*)application
183 sourceApplication:(NSString*)sourceApplication
184 annotation:(
id)annotation {
185 return [
self.lifeCycleDelegate application:application
187 sourceApplication:sourceApplication
188 annotation:annotation];
191 - (void)application:(UIApplication*)application
192 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
193 completionHandler:(
void (^)(BOOL succeeded))completionHandler {
194 [
self.lifeCycleDelegate application:application
195 performActionForShortcutItem:shortcutItem
196 completionHandler:completionHandler];
199 - (void)application:(UIApplication*)application
200 handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
201 completionHandler:(nonnull
void (^)())completionHandler {
202 [
self.lifeCycleDelegate application:application
203 handleEventsForBackgroundURLSession:identifier
204 completionHandler:completionHandler];
208 - (BOOL)application:(UIApplication*)application
209 continueUserActivity:(NSUserActivity*)userActivity
211 (
void (^)(NSArray<
id<UIUserActivityRestoring>>* __nullable restorableObjects))
213 if ([
self.lifeCycleDelegate application:application
214 continueUserActivity:userActivity
215 restorationHandler:restorationHandler]) {
219 return [
self handleOpenURL:userActivity.webpageURL options:@{} relayToSystemIfUnhandled:YES];
222 #pragma mark - FlutterPluginRegistry methods. All delegating to the rootViewController
226 if (flutterRootViewController) {
227 return [[flutterRootViewController
pluginRegistry] registrarForPlugin:pluginKey];
232 - (BOOL)hasPlugin:(NSString*)pluginKey {
234 if (flutterRootViewController) {
235 return [[flutterRootViewController
pluginRegistry] hasPlugin:pluginKey];
240 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
242 if (flutterRootViewController) {
243 return [[flutterRootViewController
pluginRegistry] valuePublishedByPlugin:pluginKey];
248 #pragma mark - Selectors handling
251 [
self.lifeCycleDelegate addDelegate:delegate];
254 #pragma mark - UIApplicationDelegate method dynamic implementation
256 - (BOOL)respondsToSelector:(
SEL)selector {
257 if ([
self.lifeCycleDelegate isSelectorAddedDynamically:selector]) {
258 return [
self delegateRespondsSelectorToPlugins:selector];
260 return [
super respondsToSelector:selector];
263 - (BOOL)delegateRespondsSelectorToPlugins:(
SEL)selector {
264 if ([
self.lifeCycleDelegate hasPluginThatRespondsToSelector:selector]) {
265 return [
self.lifeCycleDelegate respondsToSelector:selector];
271 - (id)forwardingTargetForSelector:(
SEL)aSelector {
272 if ([
self.lifeCycleDelegate isSelectorAddedDynamically:aSelector]) {
273 [
self logCapabilityConfigurationWarningIfNeeded:aSelector];
274 return self.lifeCycleDelegate;
276 return [
super forwardingTargetForSelector:aSelector];
283 - (void)logCapabilityConfigurationWarningIfNeeded:(
SEL)selector {
284 NSArray* backgroundModesArray =
285 [[NSBundle mainBundle] objectForInfoDictionaryKey:kUIBackgroundMode];
286 NSSet* backgroundModesSet = [[NSSet alloc] initWithArray:backgroundModesArray];
287 if (selector ==
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)) {
290 @"You've implemented -[<UIApplicationDelegate> "
291 @"application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need "
292 @"to add \"remote-notification\
" to the list of your supported UIBackgroundModes in your "
295 }
else if (selector ==
@selector(application:performFetchWithCompletionHandler:)) {
297 NSLog(
@"You've implemented -[<UIApplicationDelegate> "
298 @"application:performFetchWithCompletionHandler:], but you still need to add \"fetch\
" "
299 @"to the list of your supported UIBackgroundModes in your Info.plist.");
304 #pragma mark - State Restoration
306 - (BOOL)application:(UIApplication*)application shouldSaveApplicationState:(NSCoder*)coder {
307 [coder encodeInt64:self.lastAppModificationTime forKey:kRestorationStateAppModificationKey];
311 - (BOOL)application:(UIApplication*)application shouldRestoreApplicationState:(NSCoder*)coder {
312 int64_t stateDate = [coder decodeInt64ForKey:kRestorationStateAppModificationKey];
313 return self.lastAppModificationTime == stateDate;
316 - (BOOL)application:(UIApplication*)application shouldSaveSecureApplicationState:(NSCoder*)coder {
317 [coder encodeInt64:self.lastAppModificationTime forKey:kRestorationStateAppModificationKey];
321 - (BOOL)application:(UIApplication*)application
322 shouldRestoreSecureApplicationState:(NSCoder*)coder {
323 int64_t stateDate = [coder decodeInt64ForKey:kRestorationStateAppModificationKey];
324 return self.lastAppModificationTime == stateDate;
327 - (int64_t)lastAppModificationTime {
329 NSError* error = nil;
330 [[[NSBundle mainBundle] executableURL] getResourceValue:&fileDate
331 forKey:NSURLContentModificationDateKey
333 NSAssert(error == nil,
@"Cannot obtain modification date of main bundle: %@", error);
334 return [fileDate timeIntervalSince1970];