From 6e40edbeab8cf39eee91d916c98aa6a3c6921812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Sun, 11 Feb 2024 10:10:08 +0100 Subject: [PATCH] fix(ios): fix various issues related to the scene migration (#13981) * fix: map lifecycle events to scene delegates * fix(ios): migrate launch options to scene connection options * chore: restore remote notifications handler * fix: fix typo --- .../TitaniumKit/Sources/API/TiApp.m | 220 +++++++----------- 1 file changed, 85 insertions(+), 135 deletions(-) diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m index 2c6780f08ca..ec6803de5a6 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m @@ -316,106 +316,10 @@ - (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdenti - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions_ { - started = [NSDate timeIntervalSinceReferenceDate]; - [TiExceptionHandler defaultExceptionHandler]; - if ([[TiSharedConfig defaultConfig] logServerEnabled]) { - [[TiLogServer defaultLogServer] start]; - } - - // Initialize the launch options to be used by the client - launchOptions = [[NSMutableDictionary alloc] initWithDictionary:launchOptions_]; - - // If we have a APNS-UUID, assign it - NSString *apnsUUID = [[NSUserDefaults standardUserDefaults] stringForKey:@"APNSRemoteDeviceUUID"]; - if (apnsUUID != nil) { - remoteDeviceUUID = [apnsUUID copy]; - } - - [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; - - // Get some launch options to validate before finish launching. Some of them - // need to be mapepd from native to JS-types to be used by the client - NSURL *urlOptions = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; - NSString *sourceBundleId = [launchOptions objectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; - NSDictionary *_remoteNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; - UILocalNotification *_localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; - NSNumber *launchedLocation = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]; - UIApplicationShortcutItem *shortcut = [launchOptions objectForKey:UIApplicationLaunchOptionsShortcutItemKey]; - NSDictionary *userActivityDictionary = launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]; - - // Map user activity if exists - NSUserActivity *userActivity = userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"]; - if (userActivity != nil && [userActivity isKindOfClass:[NSUserActivity class]]) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{ @"activityType" : [userActivity activityType] }]; - - if ([TiUtils isIOSVersionOrGreater:@"9.0"] && [[userActivity activityType] isEqualToString:CSSearchableItemActionType]) { - if ([userActivity userInfo] != nil) { - [dict setObject:[[userActivity userInfo] objectForKey:CSSearchableItemActivityIdentifier] forKey:@"searchableItemActivityIdentifier"]; - } - } - - if ([userActivity title] != nil) { - [dict setObject:[userActivity title] forKey:@"title"]; - } - - if ([userActivity webpageURL] != nil) { - [dict setObject:[[userActivity webpageURL] absoluteString] forKey:@"webpageURL"]; - } - - if ([userActivity userInfo] != nil) { - [dict setObject:[userActivity userInfo] forKey:@"userInfo"]; - } - - // Update launchOptions so that we send only expected values rather than NSUserActivity - [launchOptions setObject:@{ @"UIApplicationLaunchOptionsUserActivityKey" : dict } - forKey:UIApplicationLaunchOptionsUserActivityDictionaryKey]; - } - - // Map background location key - if (launchedLocation != nil) { - [launchOptions setObject:launchedLocation forKey:@"launchOptionsLocationKey"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocationKey]; - } - - // Map local notification - if (_localNotification != nil) { - localNotification = [[[self class] dictionaryWithLocalNotification:_localNotification] retain]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; - - // Queue the "localnotificationaction" event for iOS 9 and lower. - // For iOS 10+, the "userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler" delegate handles it - if ([TiUtils isIOSVersionLower:@"9.0"]) { - [self tryToPostNotification:localNotification withNotificationName:kTiLocalNotificationAction completionHandler:nil]; - } - } - - // Map launched URL - if (urlOptions != nil) { - [launchOptions setObject:[urlOptions absoluteString] forKey:@"url"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; - } - - // Map launched App-ID - if (sourceBundleId != nil) { - [launchOptions setObject:sourceBundleId forKey:@"source"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; - } - - // Generate remote notification of available - if (_remoteNotification != nil) { - [self generateNotification:_remoteNotification]; - } - if (shortcut != nil) { - launchedShortcutItem = [shortcut retain]; - } - // Queue selector for usage in modules / Hyperloop [self tryToInvokeSelector:@selector(application:didFinishLaunchingWithOptions:) withArguments:[NSOrderedSet orderedSetWithObjects:application, launchOptions_, nil]]; - // If a "application-launch-url" is set, launch it directly - [self launchToUrl]; - return YES; } @@ -445,31 +349,6 @@ - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDiction return YES; } -// Handle URL-schemes / iOS < 9 -- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation -{ - [self tryToInvokeSelector:@selector(application:sourceApplication:annotation:) - withArguments:[NSOrderedSet orderedSetWithObjects:application, sourceApplication, annotation, nil]]; - - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsURLKey]; - [launchOptions setObject:[url absoluteString] forKey:@"url"]; - [launchOptions removeObjectForKey:UIApplicationLaunchOptionsSourceApplicationKey]; - - if (sourceApplication != nil) { - [launchOptions setObject:sourceApplication forKey:@"source"]; - } else { - [launchOptions removeObjectForKey:@"source"]; - } - - if (appBooted) { - [[NSNotificationCenter defaultCenter] postNotificationName:kTiApplicationLaunchedFromURL object:self userInfo:launchOptions]; - } else { - [[self queuedBootEvents] setObject:launchOptions forKey:kTiApplicationLaunchedFromURL]; - } - - return YES; -} - #pragma mark Background Fetch #ifdef USE_TI_FETCH @@ -1024,10 +903,10 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application [Webcolor flushCache]; } -- (void)applicationWillResignActive:(UIApplication *)application +- (void)sceneWillResignActive:(UIScene *)scene { - [self tryToInvokeSelector:@selector(applicationWillResignActive:) - withArguments:[NSOrderedSet orderedSetWithObject:application]]; + [self tryToInvokeSelector:@selector(sceneWillResignActive:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; if ([self forceSplashAsSnapshot]) { [window addSubview:[self splashScreenView]]; @@ -1039,13 +918,11 @@ - (void)applicationWillResignActive:(UIApplication *)application [kjsBridge gc]; } -- (void)applicationDidBecomeActive:(UIApplication *)application +- (void)sceneDidBecomeActive:(UIScene *)scene { - [self tryToInvokeSelector:@selector(applicationDidBecomeActive:) - withArguments:[NSOrderedSet orderedSetWithObject:application]]; + [self tryToInvokeSelector:@selector(sceneDidBecomeActive:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; - // We should think about placing this inside "applicationWillBecomeActive" instead to make - // the UI re-useable again more quickly if ([self forceSplashAsSnapshot] && splashScreenView != nil) { [[self splashScreenView] removeFromSuperview]; RELEASE_TO_NIL(splashScreenView); @@ -1059,10 +936,10 @@ - (void)applicationDidBecomeActive:(UIApplication *)application [[ImageLoader sharedLoader] resume]; } -- (void)applicationDidEnterBackground:(UIApplication *)application +- (void)sceneDidEnterBackground:(UIScene *)scene { - [self tryToInvokeSelector:@selector(applicationDidEnterBackground:) - withArguments:[NSOrderedSet orderedSetWithObject:application]]; + [self tryToInvokeSelector:@selector(sceneDidEnterBackground:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; @@ -1091,10 +968,10 @@ - (void)applicationDidEnterBackground:(UIApplication *)application }); } -- (void)applicationWillEnterForeground:(UIApplication *)application +- (void)sceneWillEnterForeground:(UIScene *)scene { - [self tryToInvokeSelector:@selector(applicationWillEnterForeground:) - withArguments:[NSOrderedSet orderedSetWithObject:application]]; + [self tryToInvokeSelector:@selector(sceneWillEnterForeground:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; [self flushCompletionHandlerQueue]; [sessionId release]; @@ -1230,6 +1107,79 @@ - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session op // Initialize the root-window window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene]; + // Initialize the launch options to be used by the client + launchOptions = [[NSMutableDictionary alloc] init]; + + // If we have a APNS-UUID, assign it + NSString *apnsUUID = [[NSUserDefaults standardUserDefaults] stringForKey:@"APNSRemoteDeviceUUID"]; + if (apnsUUID != nil) { + remoteDeviceUUID = [apnsUUID copy]; + } + + [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; + + // Get some launch options to validate before finish launching. Some of them + // need to be mapepd from native to JS-types to be used by the client + NSURL *urlOptions = connectionOptions.URLContexts.allObjects.firstObject.URL; + NSString *sourceBundleId = connectionOptions.sourceApplication; + UNNotificationResponse *notification = connectionOptions.notificationResponse; + UIApplicationShortcutItem *shortcut = connectionOptions.shortcutItem; + + // Map user activity if exists + NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject; + if (userActivity != nil) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{ @"activityType" : [userActivity activityType] }]; + + if ([TiUtils isIOSVersionOrGreater:@"9.0"] && [[userActivity activityType] isEqualToString:CSSearchableItemActionType]) { + if ([userActivity userInfo] != nil) { + [dict setObject:[[userActivity userInfo] objectForKey:CSSearchableItemActivityIdentifier] forKey:@"searchableItemActivityIdentifier"]; + } + } + + if ([userActivity title] != nil) { + [dict setObject:[userActivity title] forKey:@"title"]; + } + + if ([userActivity webpageURL] != nil) { + [dict setObject:[[userActivity webpageURL] absoluteString] forKey:@"webpageURL"]; + } + + if ([userActivity userInfo] != nil) { + [dict setObject:[userActivity userInfo] forKey:@"userInfo"]; + } + + // Update launchOptions so that we send only expected values rather than NSUserActivity + [launchOptions setObject:@{ @"UIApplicationLaunchOptionsUserActivityKey" : dict } + forKey:UIApplicationLaunchOptionsUserActivityDictionaryKey]; + } + + // Map launched URL + if (urlOptions != nil) { + [launchOptions setObject:[urlOptions absoluteString] forKey:@"url"]; + } + + // Map launched App-ID + if (sourceBundleId != nil) { + [launchOptions setObject:sourceBundleId forKey:@"source"]; + } + + // Generate remote notification if available + if (notification != nil && [notification.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { + [self generateNotification:@{ @"aps" : notification.notification.request.content.userInfo }]; + } + + // Save shortcut item for later + if (shortcut != nil) { + launchedShortcutItem = [shortcut retain]; + } + + // Queue selector for usage in modules / Hyperloop + [self tryToInvokeSelector:@selector(scene:willConnectToSession:options:) + withArguments:[NSOrderedSet orderedSetWithObjects:scene, connectionOptions, nil]]; + + // If a "application-launch-url" is set, launch it directly + [self launchToUrl]; + // Initialize the root-controller [self initController];