7 #include "flutter/fml/logging.h"
8 #include "flutter/fml/paths.h"
9 #include "flutter/lib/ui/plugins/callback_cache.h"
16 @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:),
17 @selector(application:performFetchWithCompletionHandler:)};
20 - (void)handleDidEnterBackground:(NSNotification*)notification
21 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
22 - (void)handleWillEnterForeground:(NSNotification*)notification
23 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
24 - (void)handleWillResignActive:(NSNotification*)notification
25 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
26 - (void)handleDidBecomeActive:(NSNotification*)notification
27 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
28 - (void)handleWillTerminate:(NSNotification*)notification
29 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
33 NSMutableArray* _notificationUnsubscribers;
40 - (void)addObserverFor:(NSString*)name selector:(
SEL)selector {
41 [[NSNotificationCenter defaultCenter] addObserver:self selector:selector name:name object:nil];
42 __block NSObject* blockSelf =
self;
43 dispatch_block_t unsubscribe = ^{
44 [[NSNotificationCenter defaultCenter] removeObserver:blockSelf name:name object:nil];
46 [_notificationUnsubscribers addObject:[[unsubscribe copy] autorelease]];
49 - (instancetype)init {
50 if (
self = [super init]) {
51 _notificationUnsubscribers = [[NSMutableArray alloc] init];
54 #if not APPLICATION_EXTENSION_API_ONLY
55 [
self addObserverFor:UIApplicationDidEnterBackgroundNotification
56 selector:@selector(handleDidEnterBackground:)];
57 [
self addObserverFor:UIApplicationWillEnterForegroundNotification
58 selector:@selector(handleWillEnterForeground:)];
59 [
self addObserverFor:UIApplicationWillResignActiveNotification
60 selector:@selector(handleWillResignActive:)];
61 [
self addObserverFor:UIApplicationDidBecomeActiveNotification
62 selector:@selector(handleDidBecomeActive:)];
63 [
self addObserverFor:UIApplicationWillTerminateNotification
64 selector:@selector(handleWillTerminate:)];
66 _delegates = [[NSPointerArray weakObjectsPointerArray] retain];
73 for (dispatch_block_t unsubscribe in _notificationUnsubscribers) {
76 [_notificationUnsubscribers release];
81 static BOOL IsPowerOfTwo(NSUInteger x) {
82 return x != 0 && (x & (x - 1)) == 0;
85 - (BOOL)isSelectorAddedDynamically:(
SEL)selector {
87 if (selector == aSelector) {
94 - (BOOL)hasPluginThatRespondsToSelector:(
SEL)selector {
95 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in [
_delegates allObjects]) {
99 if ([delegate respondsToSelector:selector]) {
107 [_delegates addPointer:(__bridge void*)delegate];
109 [_delegates compact];
113 - (BOOL)application:(UIApplication*)application
114 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
115 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in [
_delegates allObjects]) {
119 if ([delegate respondsToSelector:_cmd]) {
120 if (![delegate application:application didFinishLaunchingWithOptions:launchOptions]) {
128 - (BOOL)application:(UIApplication*)application
129 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
130 flutter::DartCallbackCache::LoadCacheFromDisk();
131 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in [
_delegates allObjects]) {
135 if ([delegate respondsToSelector:_cmd]) {
136 if (![delegate application:application willFinishLaunchingWithOptions:launchOptions]) {
144 - (void)handleDidEnterBackground:(NSNotification*)notification
145 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
146 UIApplication* application = [UIApplication sharedApplication];
147 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
154 beginBackgroundTaskWithName:@"Flutter debug task"
156 if (_debugBackgroundTask != UIBackgroundTaskInvalid) {
157 [application endBackgroundTask:_debugBackgroundTask];
158 _debugBackgroundTask = UIBackgroundTaskInvalid;
161 << "\nThe OS has terminated the Flutter debug connection for being "
162 "inactive in the background for too long.\n\n"
163 "There are no errors with your Flutter application.\n\n"
164 "To reconnect, launch your application again via 'flutter run'";
166 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
167 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
171 if ([delegate respondsToSelector:
@selector(applicationDidEnterBackground:)]) {
172 [delegate applicationDidEnterBackground:application];
177 - (void)handleWillEnterForeground:(NSNotification*)notification
178 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
179 UIApplication* application = [UIApplication sharedApplication];
180 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
182 [application endBackgroundTask:_debugBackgroundTask];
185 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
186 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
190 if ([delegate respondsToSelector:
@selector(applicationWillEnterForeground:)]) {
191 [delegate applicationWillEnterForeground:application];
196 - (void)handleWillResignActive:(NSNotification*)notification
197 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
198 UIApplication* application = [UIApplication sharedApplication];
199 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
203 if ([delegate respondsToSelector:
@selector(applicationWillResignActive:)]) {
204 [delegate applicationWillResignActive:application];
209 - (void)handleDidBecomeActive:(NSNotification*)notification
210 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
211 UIApplication* application = [UIApplication sharedApplication];
212 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
216 if ([delegate respondsToSelector:
@selector(applicationDidBecomeActive:)]) {
217 [delegate applicationDidBecomeActive:application];
222 - (void)handleWillTerminate:(NSNotification*)notification
223 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
224 UIApplication* application = [UIApplication sharedApplication];
225 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
229 if ([delegate respondsToSelector:
@selector(applicationWillTerminate:)]) {
230 [delegate applicationWillTerminate:application];
235 #pragma GCC diagnostic push
236 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
237 - (void)application:(UIApplication*)application
238 didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
239 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
243 if ([delegate respondsToSelector:_cmd]) {
244 [delegate application:application didRegisterUserNotificationSettings:notificationSettings];
248 #pragma GCC diagnostic pop
250 - (void)application:(UIApplication*)application
251 didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
252 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
256 if ([delegate respondsToSelector:_cmd]) {
257 [delegate application:application
258 didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
263 - (void)application:(UIApplication*)application
264 didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
265 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
269 if ([delegate respondsToSelector:_cmd]) {
270 [delegate application:application didFailToRegisterForRemoteNotificationsWithError:error];
275 - (void)application:(UIApplication*)application
276 didReceiveRemoteNotification:(NSDictionary*)userInfo
277 fetchCompletionHandler:(
void (^)(UIBackgroundFetchResult result))completionHandler {
278 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
282 if ([delegate respondsToSelector:_cmd]) {
283 if ([delegate application:application
284 didReceiveRemoteNotification:userInfo
285 fetchCompletionHandler:completionHandler]) {
292 #pragma GCC diagnostic push
293 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
294 - (void)application:(UIApplication*)application
295 didReceiveLocalNotification:(UILocalNotification*)notification {
296 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
300 if ([delegate respondsToSelector:_cmd]) {
301 [delegate application:application didReceiveLocalNotification:notification];
305 #pragma GCC diagnostic pop
307 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
308 willPresentNotification:(UNNotification*)notification
309 withCompletionHandler:
310 (
void (^)(UNNotificationPresentationOptions options))completionHandler {
311 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
312 if ([delegate respondsToSelector:_cmd]) {
313 [delegate userNotificationCenter:center
314 willPresentNotification:notification
315 withCompletionHandler:completionHandler];
320 - (void)userNotificationCenter:(UNUserNotificationCenter*)center
321 didReceiveNotificationResponse:(UNNotificationResponse*)response
322 withCompletionHandler:(
void (^)(
void))completionHandler {
323 for (id<FlutterApplicationLifeCycleDelegate> delegate in
_delegates) {
324 if ([delegate respondsToSelector:_cmd]) {
325 [delegate userNotificationCenter:center
326 didReceiveNotificationResponse:response
327 withCompletionHandler:completionHandler];
332 - (BOOL)application:(UIApplication*)application
334 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options {
335 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
339 if ([delegate respondsToSelector:_cmd]) {
340 if ([delegate application:application openURL:url options:options]) {
348 - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
349 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
353 if ([delegate respondsToSelector:_cmd]) {
354 if ([delegate application:application handleOpenURL:url]) {
362 - (BOOL)application:(UIApplication*)application
364 sourceApplication:(NSString*)sourceApplication
365 annotation:(
id)annotation {
366 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
370 if ([delegate respondsToSelector:_cmd]) {
371 if ([delegate application:application
373 sourceApplication:sourceApplication
374 annotation:annotation]) {
382 - (void)application:(UIApplication*)application
383 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
384 completionHandler:(
void (^)(BOOL succeeded))completionHandler {
385 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
389 if ([delegate respondsToSelector:_cmd]) {
390 if ([delegate application:application
391 performActionForShortcutItem:shortcutItem
392 completionHandler:completionHandler]) {
399 - (BOOL)application:(UIApplication*)application
400 handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
401 completionHandler:(nonnull
void (^)())completionHandler {
402 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
406 if ([delegate respondsToSelector:_cmd]) {
407 if ([delegate application:application
408 handleEventsForBackgroundURLSession:identifier
409 completionHandler:completionHandler]) {
417 - (BOOL)application:(UIApplication*)application
418 performFetchWithCompletionHandler:(
void (^)(UIBackgroundFetchResult result))completionHandler {
419 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
423 if ([delegate respondsToSelector:_cmd]) {
424 if ([delegate application:application performFetchWithCompletionHandler:completionHandler]) {
432 - (BOOL)application:(UIApplication*)application
433 continueUserActivity:(NSUserActivity*)userActivity
434 restorationHandler:(
void (^)(NSArray*))restorationHandler {
435 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
439 if ([delegate respondsToSelector:_cmd]) {
440 if ([delegate application:application
441 continueUserActivity:userActivity
442 restorationHandler:restorationHandler]) {