Skip to content

Commit

Permalink
fix(ios): fix various issues related to the scene migration (#13981)
Browse files Browse the repository at this point in the history
* fix: map lifecycle events to scene delegates

* fix(ios): migrate launch options to scene connection options

* chore: restore remote notifications handler

* fix: fix typo
  • Loading branch information
hansemannn authored Feb 11, 2024
1 parent e41650c commit 6e40edb
Showing 1 changed file with 85 additions and 135 deletions.
220 changes: 85 additions & 135 deletions iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]];
Expand All @@ -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);
Expand All @@ -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];

Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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];

Expand Down

0 comments on commit 6e40edb

Please sign in to comment.