5#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h"
7#include "flutter/fml/logging.h"
8#include "flutter/fml/paths.h"
9#include "flutter/lib/ui/plugins/callback_cache.h"
10#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
11#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h"
16 @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:),
17 @selector(application:performFetchWithCompletionHandler:)};
20- (void)handleDidEnterBackground:(NSNotification*)notification
22- (void)handleWillEnterForeground:(NSNotification*)notification
24- (void)handleWillResignActive:(NSNotification*)notification
26- (void)handleDidBecomeActive:(NSNotification*)notification
28- (void)handleWillTerminate:(NSNotification*)notification
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]];
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];
81static 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]) {
106- (void)addDelegate:(NSObject<FlutterApplicationLifeCycleDelegate>*)delegate {
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 {
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'";
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];
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]) {
static const SEL kSelectorsHandledByPlugins[]
static const char * kCallbackCacheSubDir
NSPointerArray * _delegates
UIBackgroundTaskIdentifier _debugBackgroundTask
static void LoadCacheFromDisk()
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
void setCachePath:(NSString *path)
std::string JoinPaths(std::initializer_list< std::string > components)