7 #import "flutter/fml/logging.h"
27 - (instancetype)init {
28 if (
self = [super init]) {
35 [_lifeCycleDelegate release];
36 [_rootFlutterViewControllerGetter release];
41 - (BOOL)application:(UIApplication*)application
42 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
43 return [_lifeCycleDelegate application:application willFinishLaunchingWithOptions:launchOptions];
46 - (BOOL)application:(UIApplication*)application
47 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
48 return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions];
54 if (_rootFlutterViewControllerGetter != nil) {
55 return _rootFlutterViewControllerGetter();
57 UIViewController* rootViewController = _window.rootViewController;
65 - (void)applicationDidEnterBackground:(UIApplication*)application {
69 - (void)applicationWillEnterForeground:(UIApplication*)application {
73 - (void)applicationWillResignActive:(UIApplication*)application {
77 - (void)applicationDidBecomeActive:(UIApplication*)application {
81 - (void)applicationWillTerminate:(UIApplication*)application {
84 #pragma GCC diagnostic push
85 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
86 - (void)application:(UIApplication*)application
87 didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
88 [_lifeCycleDelegate application:application
89 didRegisterUserNotificationSettings:notificationSettings];
91 #pragma GCC diagnostic pop
93 - (void)application:(UIApplication*)application
94 didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
95 [_lifeCycleDelegate application:application
96 didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
99 - (void)application:(UIApplication*)application
100 didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
101 [_lifeCycleDelegate application:application
102 didFailToRegisterForRemoteNotificationsWithError:error];
105 #pragma GCC diagnostic push
106 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
107 - (void)application:(UIApplication*)application
108 didReceiveLocalNotification:(UILocalNotification*)notification {
109 [_lifeCycleDelegate application:application didReceiveLocalNotification:notification];
111 #pragma GCC diagnostic pop
113 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
114 willPresentNotification:(UNNotification*)notification
115 withCompletionHandler:
116 (
void (^)(UNNotificationPresentationOptions options))completionHandler {
117 if ([_lifeCycleDelegate respondsToSelector:_cmd]) {
118 [_lifeCycleDelegate userNotificationCenter:center
119 willPresentNotification:notification
120 withCompletionHandler:completionHandler];
127 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
128 didReceiveNotificationResponse:(UNNotificationResponse*)response
129 withCompletionHandler:(
void (^)(
void))completionHandler {
130 if ([_lifeCycleDelegate respondsToSelector:_cmd]) {
131 [_lifeCycleDelegate userNotificationCenter:center
132 didReceiveNotificationResponse:response
133 withCompletionHandler:completionHandler];
137 - (BOOL)isFlutterDeepLinkingEnabled {
138 NSNumber* isDeepLinkingEnabled =
139 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"];
141 return isDeepLinkingEnabled ? [isDeepLinkingEnabled boolValue] : NO;
145 - (BOOL)application:(UIApplication*)application
147 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options {
148 if ([_lifeCycleDelegate application:application openURL:url options:options]) {
153 return [
self handleOpenURL:url options:options relayToSystemIfUnhandled:NO];
157 - (BOOL)handleOpenURL:(NSURL*)url
158 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options
159 relayToSystemIfUnhandled:(BOOL)throwBack {
160 if (![
self isFlutterDeepLinkingEnabled]) {
165 if (flutterViewController) {
166 [flutterViewController sendDeepLinkToFramework:url
167 completionHandler:^(BOOL success) {
168 if (!success && throwBack) {
170 [UIApplication.sharedApplication openURL:url];
174 FML_LOG(ERROR) <<
"Attempting to open an URL without a Flutter RootViewController.";
180 - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
181 return [_lifeCycleDelegate application:application handleOpenURL:url];
184 - (BOOL)application:(UIApplication*)application
186 sourceApplication:(NSString*)sourceApplication
187 annotation:(
id)annotation {
188 return [_lifeCycleDelegate application:application
190 sourceApplication:sourceApplication
191 annotation:annotation];
194 - (void)application:(UIApplication*)application
195 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
196 completionHandler:(
void (^)(BOOL succeeded))completionHandler {
197 [_lifeCycleDelegate application:application
198 performActionForShortcutItem:shortcutItem
199 completionHandler:completionHandler];
202 - (void)application:(UIApplication*)application
203 handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
204 completionHandler:(nonnull
void (^)())completionHandler {
205 [_lifeCycleDelegate application:application
206 handleEventsForBackgroundURLSession:identifier
207 completionHandler:completionHandler];
211 - (BOOL)application:(UIApplication*)application
212 continueUserActivity:(NSUserActivity*)userActivity
214 (
void (^)(NSArray<
id<UIUserActivityRestoring>>* __nullable restorableObjects))
216 if ([_lifeCycleDelegate application:application
217 continueUserActivity:userActivity
218 restorationHandler:restorationHandler]) {
222 return [
self handleOpenURL:userActivity.webpageURL options:@{} relayToSystemIfUnhandled:YES];
225 #pragma mark - FlutterPluginRegistry methods. All delegating to the rootViewController
229 if (flutterRootViewController) {
230 return [[flutterRootViewController
pluginRegistry] registrarForPlugin:pluginKey];
235 - (BOOL)hasPlugin:(NSString*)pluginKey {
237 if (flutterRootViewController) {
238 return [[flutterRootViewController
pluginRegistry] hasPlugin:pluginKey];
243 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
245 if (flutterRootViewController) {
246 return [[flutterRootViewController
pluginRegistry] valuePublishedByPlugin:pluginKey];
251 #pragma mark - Selectors handling
254 [_lifeCycleDelegate addDelegate:delegate];
257 #pragma mark - UIApplicationDelegate method dynamic implementation
259 - (BOOL)respondsToSelector:(
SEL)selector {
260 if ([_lifeCycleDelegate isSelectorAddedDynamically:selector]) {
261 return [
self delegateRespondsSelectorToPlugins:selector];
263 return [
super respondsToSelector:selector];
266 - (BOOL)delegateRespondsSelectorToPlugins:(
SEL)selector {
267 if ([_lifeCycleDelegate hasPluginThatRespondsToSelector:selector]) {
268 return [_lifeCycleDelegate respondsToSelector:selector];
274 - (id)forwardingTargetForSelector:(
SEL)aSelector {
275 if ([_lifeCycleDelegate isSelectorAddedDynamically:aSelector]) {
276 [
self logCapabilityConfigurationWarningIfNeeded:aSelector];
277 return _lifeCycleDelegate;
279 return [
super forwardingTargetForSelector:aSelector];
286 - (void)logCapabilityConfigurationWarningIfNeeded:(
SEL)selector {
287 NSArray* backgroundModesArray =
288 [[NSBundle mainBundle] objectForInfoDictionaryKey:kUIBackgroundMode];
289 NSSet* backgroundModesSet = [[[NSSet alloc] initWithArray:backgroundModesArray] autorelease];
290 if (selector ==
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)) {
293 @"You've implemented -[<UIApplicationDelegate> "
294 @"application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need "
295 @"to add \"remote-notification\
" to the list of your supported UIBackgroundModes in your "
298 }
else if (selector ==
@selector(application:performFetchWithCompletionHandler:)) {
300 NSLog(
@"You've implemented -[<UIApplicationDelegate> "
301 @"application:performFetchWithCompletionHandler:], but you still need to add \"fetch\
" "
302 @"to the list of your supported UIBackgroundModes in your Info.plist.");
307 #pragma mark - State Restoration
309 - (BOOL)application:(UIApplication*)application shouldSaveApplicationState:(NSCoder*)coder {
310 [coder encodeInt64:self.lastAppModificationTime forKey:kRestorationStateAppModificationKey];
314 - (BOOL)application:(UIApplication*)application shouldRestoreApplicationState:(NSCoder*)coder {
315 int64_t stateDate = [coder decodeInt64ForKey:kRestorationStateAppModificationKey];
316 return self.lastAppModificationTime == stateDate;
319 - (BOOL)application:(UIApplication*)application shouldSaveSecureApplicationState:(NSCoder*)coder {
320 [coder encodeInt64:self.lastAppModificationTime forKey:kRestorationStateAppModificationKey];
324 - (BOOL)application:(UIApplication*)application
325 shouldRestoreSecureApplicationState:(NSCoder*)coder {
326 int64_t stateDate = [coder decodeInt64ForKey:kRestorationStateAppModificationKey];
327 return self.lastAppModificationTime == stateDate;
330 - (int64_t)lastAppModificationTime {
332 NSError* error = nil;
333 [[[NSBundle mainBundle] executableURL] getResourceValue:&fileDate
334 forKey:NSURLContentModificationDateKey
336 NSAssert(error == nil,
@"Cannot obtain modification date of main bundle: %@", error);
337 return [fileDate timeIntervalSince1970];