7 #import "flutter/fml/logging.h"
28 - (instancetype)init {
29 if (
self = [super init]) {
35 - (BOOL)application:(UIApplication*)application
36 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
37 return [
self.lifeCycleDelegate application:application
38 willFinishLaunchingWithOptions:launchOptions];
41 - (BOOL)application:(UIApplication*)application
42 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
43 return [
self.lifeCycleDelegate application:application
44 didFinishLaunchingWithOptions:launchOptions];
50 if (_rootFlutterViewControllerGetter != nil) {
51 return _rootFlutterViewControllerGetter();
53 UIViewController* rootViewController = _window.rootViewController;
61 - (void)applicationDidEnterBackground:(UIApplication*)application {
65 - (void)applicationWillEnterForeground:(UIApplication*)application {
69 - (void)applicationWillResignActive:(UIApplication*)application {
73 - (void)applicationDidBecomeActive:(UIApplication*)application {
77 - (void)applicationWillTerminate:(UIApplication*)application {
80 #pragma GCC diagnostic push
81 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
82 - (void)application:(UIApplication*)application
83 didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
84 [
self.lifeCycleDelegate application:application
85 didRegisterUserNotificationSettings:notificationSettings];
87 #pragma GCC diagnostic pop
89 - (void)application:(UIApplication*)application
90 didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
91 [
self.lifeCycleDelegate application:application
92 didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
95 - (void)application:(UIApplication*)application
96 didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
97 [
self.lifeCycleDelegate application:application
98 didFailToRegisterForRemoteNotificationsWithError:error];
101 #pragma GCC diagnostic push
102 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
103 - (void)application:(UIApplication*)application
104 didReceiveLocalNotification:(UILocalNotification*)notification {
105 [
self.lifeCycleDelegate application:application didReceiveLocalNotification:notification];
107 #pragma GCC diagnostic pop
109 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
110 willPresentNotification:(UNNotification*)notification
111 withCompletionHandler:
112 (
void (^)(UNNotificationPresentationOptions options))completionHandler {
113 if ([
self.lifeCycleDelegate respondsToSelector:_cmd]) {
114 [
self.lifeCycleDelegate userNotificationCenter:center
115 willPresentNotification:notification
116 withCompletionHandler:completionHandler];
123 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
124 didReceiveNotificationResponse:(UNNotificationResponse*)response
125 withCompletionHandler:(
void (^)(
void))completionHandler {
126 if ([
self.lifeCycleDelegate respondsToSelector:_cmd]) {
127 [
self.lifeCycleDelegate userNotificationCenter:center
128 didReceiveNotificationResponse:response
129 withCompletionHandler:completionHandler];
133 - (BOOL)isFlutterDeepLinkingEnabled {
134 NSNumber* isDeepLinkingEnabled =
135 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"];
137 return isDeepLinkingEnabled ? [isDeepLinkingEnabled boolValue] : YES;
141 - (BOOL)application:(UIApplication*)application
143 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options {
144 if ([
self.lifeCycleDelegate application:application openURL:url options:options]) {
149 return [
self handleOpenURL:url options:options relayToSystemIfUnhandled:NO];
153 - (BOOL)handleOpenURL:(NSURL*)url
154 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options
155 relayToSystemIfUnhandled:(BOOL)throwBack {
156 if (![
self isFlutterDeepLinkingEnabled]) {
161 if (flutterViewController) {
162 [flutterViewController sendDeepLinkToFramework:url
163 completionHandler:^(BOOL success) {
164 if (!success && throwBack) {
166 [UIApplication.sharedApplication openURL:url];
170 FML_LOG(ERROR) <<
"Attempting to open an URL without a Flutter RootViewController.";
176 - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
177 return [
self.lifeCycleDelegate application:application handleOpenURL:url];
180 - (BOOL)application:(UIApplication*)application
182 sourceApplication:(NSString*)sourceApplication
183 annotation:(
id)annotation {
184 return [
self.lifeCycleDelegate application:application
186 sourceApplication:sourceApplication
187 annotation:annotation];
190 - (void)application:(UIApplication*)application
191 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
192 completionHandler:(
void (^)(BOOL succeeded))completionHandler {
193 [
self.lifeCycleDelegate application:application
194 performActionForShortcutItem:shortcutItem
195 completionHandler:completionHandler];
198 - (void)application:(UIApplication*)application
199 handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
200 completionHandler:(nonnull
void (^)())completionHandler {
201 [
self.lifeCycleDelegate application:application
202 handleEventsForBackgroundURLSession:identifier
203 completionHandler:completionHandler];
207 - (BOOL)application:(UIApplication*)application
208 continueUserActivity:(NSUserActivity*)userActivity
210 (
void (^)(NSArray<
id<UIUserActivityRestoring>>* __nullable restorableObjects))
212 if ([
self.lifeCycleDelegate application:application
213 continueUserActivity:userActivity
214 restorationHandler:restorationHandler]) {
218 return [
self handleOpenURL:userActivity.webpageURL options:@{} relayToSystemIfUnhandled:YES];
221 #pragma mark - FlutterPluginRegistry methods. All delegating to the rootViewController
225 if (flutterRootViewController) {
226 return [[flutterRootViewController
pluginRegistry] registrarForPlugin:pluginKey];
231 - (BOOL)hasPlugin:(NSString*)pluginKey {
233 if (flutterRootViewController) {
234 return [[flutterRootViewController
pluginRegistry] hasPlugin:pluginKey];
239 - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
241 if (flutterRootViewController) {
242 return [[flutterRootViewController
pluginRegistry] valuePublishedByPlugin:pluginKey];
247 #pragma mark - Selectors handling
250 [
self.lifeCycleDelegate addDelegate:delegate];
253 #pragma mark - UIApplicationDelegate method dynamic implementation
255 - (BOOL)respondsToSelector:(
SEL)selector {
256 if ([
self.lifeCycleDelegate isSelectorAddedDynamically:selector]) {
257 return [
self delegateRespondsSelectorToPlugins:selector];
259 return [
super respondsToSelector:selector];
262 - (BOOL)delegateRespondsSelectorToPlugins:(
SEL)selector {
263 if ([
self.lifeCycleDelegate hasPluginThatRespondsToSelector:selector]) {
264 return [
self.lifeCycleDelegate respondsToSelector:selector];
270 - (id)forwardingTargetForSelector:(
SEL)aSelector {
271 if ([
self.lifeCycleDelegate isSelectorAddedDynamically:aSelector]) {
272 [
self logCapabilityConfigurationWarningIfNeeded:aSelector];
273 return self.lifeCycleDelegate;
275 return [
super forwardingTargetForSelector:aSelector];
282 - (void)logCapabilityConfigurationWarningIfNeeded:(
SEL)selector {
283 NSArray* backgroundModesArray =
284 [[NSBundle mainBundle] objectForInfoDictionaryKey:kUIBackgroundMode];
285 NSSet* backgroundModesSet = [[NSSet alloc] initWithArray:backgroundModesArray];
286 if (selector ==
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)) {
289 @"You've implemented -[<UIApplicationDelegate> "
290 @"application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need "
291 @"to add \"remote-notification\
" to the list of your supported UIBackgroundModes in your "
294 }
else if (selector ==
@selector(application:performFetchWithCompletionHandler:)) {
296 NSLog(
@"You've implemented -[<UIApplicationDelegate> "
297 @"application:performFetchWithCompletionHandler:], but you still need to add \"fetch\
" "
298 @"to the list of your supported UIBackgroundModes in your Info.plist.");
303 #pragma mark - State Restoration
305 - (BOOL)application:(UIApplication*)application shouldSaveApplicationState:(NSCoder*)coder {
306 [coder encodeInt64:self.lastAppModificationTime forKey:kRestorationStateAppModificationKey];
310 - (BOOL)application:(UIApplication*)application shouldRestoreApplicationState:(NSCoder*)coder {
311 int64_t stateDate = [coder decodeInt64ForKey:kRestorationStateAppModificationKey];
312 return self.lastAppModificationTime == stateDate;
315 - (BOOL)application:(UIApplication*)application shouldSaveSecureApplicationState:(NSCoder*)coder {
316 [coder encodeInt64:self.lastAppModificationTime forKey:kRestorationStateAppModificationKey];
320 - (BOOL)application:(UIApplication*)application
321 shouldRestoreSecureApplicationState:(NSCoder*)coder {
322 int64_t stateDate = [coder decodeInt64ForKey:kRestorationStateAppModificationKey];
323 return self.lastAppModificationTime == stateDate;
326 - (int64_t)lastAppModificationTime {
328 NSError* error = nil;
329 [[[NSBundle mainBundle] executableURL] getResourceValue:&fileDate
330 forKey:NSURLContentModificationDateKey
332 NSAssert(error == nil,
@"Cannot obtain modification date of main bundle: %@", error);
333 return [fileDate timeIntervalSince1970];