From 3513427fb19724bbf83bd16181a4f89ac0b0e53c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Sat, 4 May 2024 20:34:57 +0200 Subject: [PATCH] fix(ios): fix duplicate application delegate allocation --- iphone/Classes/TiApp+Scenes.h | 12 + iphone/Classes/TiApp+Scenes.m | 223 ++++++++++++++++++ .../TitaniumKit.xcodeproj/project.pbxproj | 10 +- .../TitaniumKit/Sources/API/TiApp.h | 42 +++- .../TitaniumKit/Sources/API/TiApp.m | 221 +---------------- .../TitaniumKit/Sources/API/TiSceneDelegate.h | 14 ++ .../TitaniumKit/Sources/API/TiSceneDelegate.m | 48 ++++ iphone/iphone/Titanium.plist | 2 +- .../iphone/Titanium.xcodeproj/project.pbxproj | 8 +- 9 files changed, 358 insertions(+), 222 deletions(-) create mode 100644 iphone/Classes/TiApp+Scenes.h create mode 100644 iphone/Classes/TiApp+Scenes.m create mode 100644 iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.h create mode 100644 iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.m diff --git a/iphone/Classes/TiApp+Scenes.h b/iphone/Classes/TiApp+Scenes.h new file mode 100644 index 00000000000..43048d1e2e2 --- /dev/null +++ b/iphone/Classes/TiApp+Scenes.h @@ -0,0 +1,12 @@ +// +// TiApp+Scenes.h +// Titanium +// +// Created by Hans Knöchel on 04.05.24. +// + +#import + +@interface TiApp (Scenes) + +@end diff --git a/iphone/Classes/TiApp+Scenes.m b/iphone/Classes/TiApp+Scenes.m new file mode 100644 index 00000000000..ae96683f4cb --- /dev/null +++ b/iphone/Classes/TiApp+Scenes.m @@ -0,0 +1,223 @@ +// +// TiApp+Scenes.m +// Titanium +// +// Created by Hans Knöchel on 04.05.24. +// + +#import "TiApp+Scenes.h" + +#import + +#import +#import +#import + +@implementation TiApp (Scenes) + +- (void)sceneWillResignActive:(UIScene *)scene +{ + [self tryToInvokeSelector:@selector(sceneWillResignActive:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; + + if ([self forceSplashAsSnapshot]) { + [window addSubview:[self splashScreenView]]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:kTiSuspendNotification object:self]; + + // suspend any image loading + [[ImageLoader sharedLoader] suspend]; + [kjsBridge gc]; +} + +- (void)sceneDidBecomeActive:(UIScene *)scene +{ + [self tryToInvokeSelector:@selector(sceneDidBecomeActive:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; + + if ([self forceSplashAsSnapshot] && splashScreenView != nil) { + [[self splashScreenView] removeFromSuperview]; + RELEASE_TO_NIL(splashScreenView); + } + + // NOTE: Have to fire a separate but non-'resume' event here because there is SOME information + // (like new URL) that is not passed through as part of the normal foregrounding process. + [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumedNotification object:self]; + + // resume any image loading + [[ImageLoader sharedLoader] resume]; +} + +- (void)sceneDidEnterBackground:(UIScene *)scene +{ + [self tryToInvokeSelector:@selector(sceneDidEnterBackground:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; + + if (backgroundServices == nil) { + return; + } + + UIApplication *app = [UIApplication sharedApplication]; + TiApp *tiapp = self; + bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ + // Synchronize the cleanup call on the main thread in case + // the task actually finishes at around the same time. + TiThreadPerformOnMainThread( + ^{ + if (bgTask != UIBackgroundTaskInvalid) { + [app endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + } + }, + NO); + }]; + // Start the long-running task and return immediately. + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // Do the work associated with the task. + [tiapp beginBackgrounding]; + }); +} + +- (void)sceneWillEnterForeground:(UIScene *)scene +{ + [self tryToInvokeSelector:@selector(sceneWillEnterForeground:) + withArguments:[NSOrderedSet orderedSetWithObject:scene]]; + + [self flushCompletionHandlerQueue]; + [sessionId release]; + sessionId = [[TiUtils createUUID] retain]; + + //TIMOB-3432. Ensure url is cleared when resume event is fired. + [launchOptions removeObjectForKey:@"url"]; + [launchOptions removeObjectForKey:@"source"]; + + [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumeNotification object:self]; + + if (backgroundServices == nil) { + return; + } + + [self endBackgrounding]; +} + +- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts +{ + UIOpenURLContext *primaryContext = URLContexts.allObjects.firstObject; + + NSDictionary *options = @{ + UIApplicationOpenURLOptionsSourceApplicationKey : NULL_IF_NIL(primaryContext.options.sourceApplication) + }; + + [self application:[UIApplication sharedApplication] openURL:primaryContext.URL options:options]; +} + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options +{ + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; +} + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions +{ + // Initialize the root-window + window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene]; + + // Initialize the launch options to be used by the client + launchOptions = [[NSMutableDictionary alloc] init]; + + // Retain connectionOptions for later use + if (self.connectionOptions != connectionOptions) { + [self.connectionOptions release]; // Release any existing object + self.connectionOptions = [connectionOptions retain]; // Retain the new object + } + + // 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]]; + + // Catch exceptions + [TiExceptionHandler defaultExceptionHandler]; + + // Enable device logs (e.g. for physical devices) + if ([[TiSharedConfig defaultConfig] logServerEnabled]) { + [[TiLogServer defaultLogServer] start]; + } + + // Initialize the root-controller + [self initController]; + + // If a "application-launch-url" is set, launch it directly + [self launchToUrl]; + + // Boot our kroll-core + [self boot]; + + // Create application support directory if not exists + [self createDefaultDirectories]; +} + +@end diff --git a/iphone/TitaniumKit/TitaniumKit.xcodeproj/project.pbxproj b/iphone/TitaniumKit/TitaniumKit.xcodeproj/project.pbxproj index 9edd4a2fad5..8375099c54f 100644 --- a/iphone/TitaniumKit/TitaniumKit.xcodeproj/project.pbxproj +++ b/iphone/TitaniumKit/TitaniumKit.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -21,6 +21,8 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 3A39A6B12BE6AFFB0019C843 /* TiSceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A39A6B02BE6AFFB0019C843 /* TiSceneDelegate.m */; }; + 3A39A6B22BE6AFFB0019C843 /* TiSceneDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A39A6AF2BE6AFFB0019C843 /* TiSceneDelegate.h */; }; 4A175276218B64E70094C7B6 /* KrollTimerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A175274218B64E70094C7B6 /* KrollTimerManager.h */; }; 4A175277218B64E70094C7B6 /* KrollTimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A175275218B64E70094C7B6 /* KrollTimerManager.m */; }; 4A1FF4432523262A00A0F923 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A1FF4422523262A00A0F923 /* ErrorView.swift */; }; @@ -191,6 +193,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 3A39A6AF2BE6AFFB0019C843 /* TiSceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TiSceneDelegate.h; sourceTree = ""; }; + 3A39A6B02BE6AFFB0019C843 /* TiSceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TiSceneDelegate.m; sourceTree = ""; }; 4A175274218B64E70094C7B6 /* KrollTimerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KrollTimerManager.h; sourceTree = ""; }; 4A175275218B64E70094C7B6 /* KrollTimerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KrollTimerManager.m; sourceTree = ""; }; 4A1FF4422523262A00A0F923 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; @@ -504,6 +508,8 @@ DB15FD051F0A892500A82C45 /* Ti3DMatrix.m */, DB15FC921F0A860600A82C45 /* TiAnimation.h */, DB15FC931F0A860600A82C45 /* TiAnimation.m */, + 3A39A6AF2BE6AFFB0019C843 /* TiSceneDelegate.h */, + 3A39A6B02BE6AFFB0019C843 /* TiSceneDelegate.m */, DB15FC4B1F0A848200A82C45 /* TiApp.h */, DB15FC4C1F0A848200A82C45 /* TiApp.m */, DB258D231F097680000D0D8D /* TiBase.h */, @@ -723,6 +729,7 @@ DB15FD201F0A8A5E00A82C45 /* TiComplexValue.h in Headers */, DB5813E72075FCF200CA1437 /* TiDefines.h in Headers */, DB24E0502076824C0033B2B1 /* TiSharedConfig.h in Headers */, + 3A39A6B22BE6AFFB0019C843 /* TiSceneDelegate.h in Headers */, DB15FC3D1F0A833100A82C45 /* KrollObject.h in Headers */, DB15FCA81F0A866300A82C45 /* TiRect.h in Headers */, DB15FC891F0A859800A82C45 /* TiExceptionHandler.h in Headers */, @@ -834,6 +841,7 @@ files = ( DB15FD091F0A892500A82C45 /* Ti3DMatrix.m in Sources */, DB15FCB91F0A874F00A82C45 /* TopTiModule.m in Sources */, + 3A39A6B12BE6AFFB0019C843 /* TiSceneDelegate.m in Sources */, DB15FC4E1F0A848200A82C45 /* TiApp.m in Sources */, DB15FCB11F0A86E600A82C45 /* TiBindingTiValue.m in Sources */, DB15FC461F0A838E00A82C45 /* TiColor.m in Sources */, diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.h b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.h index 909962df8c5..55b5632220f 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.h +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.h @@ -16,7 +16,7 @@ /** TiApp represents an instance of an application. There is always only one instance per application which could be accessed through class method. */ -@interface TiApp : TiHost { +@interface TiApp : TiHost { UIWindow *window; UIImageView *loadView; UIView *splashScreenView; @@ -113,13 +113,6 @@ */ @property (nonatomic, readonly) NSDictionary *localNotification; -/** - Returns details for the last remote notification. - - Dictionary containing details about remote notification, or _nil_. - */ -@property (nonatomic, readonly) UISceneConnectionOptions *connectionOptions; - /** Returns the application's root view controller. */ @@ -276,6 +269,23 @@ */ - (void)tryToInvokeSelector:(SEL)selector withArguments:(NSOrderedSet *)arguments; +/** + Returns details for the last remote notification. + + Dictionary containing details about remote notification, or _nil_. + */ +@property (nonatomic, strong) UISceneConnectionOptions *connectionOptions; + +/** + The splash screen view used when the app is booted. + */ +- (UIView *)splashScreenView; + +/** + Clear out the pending completion handlers. + */ +- (void)flushCompletionHandlerQueue; + /** Tries to post a given notification with the given name. If the app did not finish launching so far, it will be queued and processed once the JSCore bridge is ready. @@ -302,4 +312,20 @@ - (void)performCompletionHandlerForBackgroundTransferWithKey:(NSString *)key; - (void)watchKitExtensionRequestHandler:(id)key withUserInfo:(NSDictionary *)userInfo; +#pragma mark UIWindowSceneDelegate + +- (void)sceneWillResignActive:(UIScene *)scene; + +- (void)sceneDidBecomeActive:(UIScene *)scene; + +- (void)sceneDidEnterBackground:(UIScene *)scene; + +- (void)sceneWillEnterForeground:(UIScene *)scene; + +- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts; + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options; + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions; + @end diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m index e1f0efd6090..30f70a730e7 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m @@ -128,10 +128,17 @@ - (NSDictionary *)launchOptions return _applicationDelegates; } -- (void)initController +- (instancetype)init { - sharedApp = self; + if (self = [super init]) { + sharedApp = self; + } + + return self; +} +- (void)initController +{ // attach our main view controller controller = [[TiRootViewController alloc] init]; // attach our main view controller... IF we haven't already loaded the main window. @@ -324,19 +331,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( return YES; } -- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts -{ - UIOpenURLContext *primaryContext = URLContexts.allObjects.firstObject; - - NSDictionary *options = @{ - UIApplicationOpenURLOptionsSourceApplicationKey : NULL_IF_NIL(primaryContext.options.sourceApplication) - }; - - [self application:[UIApplication sharedApplication] openURL:primaryContext.URL options:options]; -} - // Handle URL-schemes. Note that this selector is not called automatically anymore in iOS 13+ -// because of the scene management. Instead, the above "scene:openURLContexts:" selector is called +// because of the scene management. Instead, the "scene:openURLContexts:" selector is called // that forwards the call for maximum backwards compatibility - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { @@ -636,7 +632,6 @@ - (void)tryToPostBackgroundModeNotification:(NSMutableDictionary *)userInfo with } } -// Clear out the pending completion handlers - (void)flushCompletionHandlerQueue { if (pendingCompletionHandlers != nil) { @@ -917,93 +912,6 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application [Webcolor flushCache]; } -- (void)sceneWillResignActive:(UIScene *)scene -{ - [self tryToInvokeSelector:@selector(sceneWillResignActive:) - withArguments:[NSOrderedSet orderedSetWithObject:scene]]; - - if ([self forceSplashAsSnapshot]) { - [window addSubview:[self splashScreenView]]; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kTiSuspendNotification object:self]; - - // suspend any image loading - [[ImageLoader sharedLoader] suspend]; - [kjsBridge gc]; -} - -- (void)sceneDidBecomeActive:(UIScene *)scene -{ - [self tryToInvokeSelector:@selector(sceneDidBecomeActive:) - withArguments:[NSOrderedSet orderedSetWithObject:scene]]; - - if ([self forceSplashAsSnapshot] && splashScreenView != nil) { - [[self splashScreenView] removeFromSuperview]; - RELEASE_TO_NIL(splashScreenView); - } - - // NOTE: Have to fire a separate but non-'resume' event here because there is SOME information - // (like new URL) that is not passed through as part of the normal foregrounding process. - [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumedNotification object:self]; - - // resume any image loading - [[ImageLoader sharedLoader] resume]; -} - -- (void)sceneDidEnterBackground:(UIScene *)scene -{ - [self tryToInvokeSelector:@selector(sceneDidEnterBackground:) - withArguments:[NSOrderedSet orderedSetWithObject:scene]]; - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self]; - - if (backgroundServices == nil) { - return; - } - - UIApplication *app = [UIApplication sharedApplication]; - TiApp *tiapp = self; - bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ - // Synchronize the cleanup call on the main thread in case - // the task actually finishes at around the same time. - TiThreadPerformOnMainThread( - ^{ - if (bgTask != UIBackgroundTaskInvalid) { - [app endBackgroundTask:bgTask]; - bgTask = UIBackgroundTaskInvalid; - } - }, - NO); - }]; - // Start the long-running task and return immediately. - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - // Do the work associated with the task. - [tiapp beginBackgrounding]; - }); -} - -- (void)sceneWillEnterForeground:(UIScene *)scene -{ - [self tryToInvokeSelector:@selector(sceneWillEnterForeground:) - withArguments:[NSOrderedSet orderedSetWithObject:scene]]; - - [self flushCompletionHandlerQueue]; - [sessionId release]; - sessionId = [[TiUtils createUUID] retain]; - - //TIMOB-3432. Ensure url is cleared when resume event is fired. - [launchOptions removeObjectForKey:@"url"]; - [launchOptions removeObjectForKey:@"source"]; - - [[NSNotificationCenter defaultCenter] postNotificationName:kTiResumeNotification object:self]; - - if (backgroundServices == nil) { - return; - } - - [self endBackgrounding]; -} - //TODO: this should be compiled out in production mode - (void)showModalError:(NSString *)message { @@ -1110,115 +1018,6 @@ - (KrollBridge *)krollBridge return kjsBridge; } -#pragma mark UIWindowSceneDelegate - -- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options -{ - return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; -} - -- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions -{ - // Initialize the root-window - window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene]; - - // Initialize the launch options to be used by the client - launchOptions = [[NSMutableDictionary alloc] init]; - - // Retain connectionOptions for later use - if (_connectionOptions != connectionOptions) { - [_connectionOptions release]; // Release any existing object - _connectionOptions = [connectionOptions retain]; // Retain the new object - } - - // 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]]; - - // Catch exceptions - [TiExceptionHandler defaultExceptionHandler]; - - // Enable device logs (e.g. for physical devices) - if ([[TiSharedConfig defaultConfig] logServerEnabled]) { - [[TiLogServer defaultLogServer] start]; - } - - // Initialize the root-controller - [self initController]; - - // If a "application-launch-url" is set, launch it directly - [self launchToUrl]; - - // Boot our kroll-core - [self boot]; - - // Create application support directory if not exists - [self createDefaultDirectories]; -} - #pragma mark Background Tasks - (void)beginBackgrounding diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.h b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.h new file mode 100644 index 00000000000..a53a59acf11 --- /dev/null +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.h @@ -0,0 +1,14 @@ +// +// TiSceneDelegate.h +// TitaniumKit +// +// Created by Hans Knöchel on 04.05.24. +// Copyright © 2024 Hans Knoechel. All rights reserved. +// + +#import +#import + +@interface TiSceneDelegate : UIResponder + +@end diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.m new file mode 100644 index 00000000000..c9c2e4742f0 --- /dev/null +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiSceneDelegate.m @@ -0,0 +1,48 @@ +// +// TiSceneDelegate.m +// TitaniumKit +// +// Created by Hans Knöchel on 04.05.24. +// Copyright © 2024 Hans Knoechel. All rights reserved. +// + +#import "TiSceneDelegate.h" + +@implementation TiSceneDelegate + +- (void)sceneWillResignActive:(UIScene *)scene +{ + [[TiApp app] sceneWillResignActive:scene]; +} + +- (void)sceneDidBecomeActive:(UIScene *)scene +{ + [[TiApp app] sceneDidBecomeActive:scene]; +} + +- (void)sceneDidEnterBackground:(UIScene *)scene +{ + [[TiApp app] sceneDidEnterBackground:scene]; +} + +- (void)sceneWillEnterForeground:(UIScene *)scene +{ + [[TiApp app] sceneWillEnterForeground:scene]; +} + +- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts +{ + [[TiApp app] scene:scene openURLContexts:URLContexts]; +} + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options +{ + return [[TiApp app] application:application configurationForConnectingSceneSession:connectingSceneSession options:options]; +} + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions +{ + [[TiApp app] scene:scene willConnectToSession:session options:connectionOptions]; +} + +@end diff --git a/iphone/iphone/Titanium.plist b/iphone/iphone/Titanium.plist index 448f4c87fe8..1e6228e5aeb 100644 --- a/iphone/iphone/Titanium.plist +++ b/iphone/iphone/Titanium.plist @@ -90,7 +90,7 @@ UISceneConfigurationName Default Configuration UISceneDelegateClassName - TiApp + TiSceneDelegate diff --git a/iphone/iphone/Titanium.xcodeproj/project.pbxproj b/iphone/iphone/Titanium.xcodeproj/project.pbxproj index a00c3e2c5c4..36a773edca6 100644 --- a/iphone/iphone/Titanium.xcodeproj/project.pbxproj +++ b/iphone/iphone/Titanium.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -161,6 +161,7 @@ 3A1E40511BEAC73D00943233 /* TiUIiOSMenuPopup.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A1E40501BEAC73D00943233 /* TiUIiOSMenuPopup.m */; }; 3A275F3E1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A275F3D1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.m */; }; 3A38F30424D6EBBD00CC6EFB /* TiUtils+Addons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A38F30324D6EBBD00CC6EFB /* TiUtils+Addons.swift */; }; + 3A39A6B52BE6B1360019C843 /* TiApp+Scenes.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A39A6B42BE6B1360019C843 /* TiApp+Scenes.m */; }; 3A3BBAF51D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3BBAF41D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m */; }; 3A527EB327E0F77700A470D6 /* TiUITableViewScrollPositionProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A527EB227E0F77700A470D6 /* TiUITableViewScrollPositionProxy.m */; }; 3A5AD7261BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A5AD7251BB9A6E4005B408B /* TiUIiOSPreviewActionGroupProxy.m */; }; @@ -609,6 +610,8 @@ 3A275F3C1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIActivityIndicatorStyleProxy.h; sourceTree = ""; }; 3A275F3D1BA881B300EC4912 /* TiUIActivityIndicatorStyleProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIActivityIndicatorStyleProxy.m; sourceTree = ""; }; 3A38F30324D6EBBD00CC6EFB /* TiUtils+Addons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TiUtils+Addons.swift"; sourceTree = ""; }; + 3A39A6B32BE6B1360019C843 /* TiApp+Scenes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TiApp+Scenes.h"; sourceTree = ""; }; + 3A39A6B42BE6B1360019C843 /* TiApp+Scenes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "TiApp+Scenes.m"; sourceTree = ""; }; 3A3BBAF31D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiAppiOSUserNotificationCenterProxy.h; sourceTree = ""; }; 3A3BBAF41D3E2F0F008450DF /* TiAppiOSUserNotificationCenterProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiAppiOSUserNotificationCenterProxy.m; sourceTree = ""; }; 3A527EB027E0F77700A470D6 /* TiUITableViewScrollPositionProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUITableViewScrollPositionProxy.h; sourceTree = ""; }; @@ -1984,6 +1987,8 @@ DBF30945210F3B420001F770 /* TiApp+Addons.h */, DBF30946210F3B420001F770 /* TiApp+Addons.m */, 3A38F30324D6EBBD00CC6EFB /* TiUtils+Addons.swift */, + 3A39A6B32BE6B1360019C843 /* TiApp+Scenes.h */, + 3A39A6B42BE6B1360019C843 /* TiApp+Scenes.m */, DBF30942210F37080001F770 /* TiWindowProxy+Addons.h */, DBF30943210F37080001F770 /* TiWindowProxy+Addons.m */, ); @@ -2178,6 +2183,7 @@ 24CA8B92111161FE0084E2DE /* TiUISearchBar.m in Sources */, 6CF8E95921CDA58800519245 /* TiUITabbedBarProxy.m in Sources */, 84DEE9171815CF52000D7B78 /* TiUIRefreshControlProxy.m in Sources */, + 3A39A6B52BE6B1360019C843 /* TiApp+Scenes.m in Sources */, 159C599B1C383645009A8860 /* TiUIiOSTableViewCellSelectionStyleProxy.m in Sources */, 24CA8B95111161FE0084E2DE /* TiUIProgressBarProxy.m in Sources */, 3AA4EC262320352B00703A20 /* TiUIListView.m in Sources */,