diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist index b88dfae5b28..f40afda55e0 100644 --- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist +++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist @@ -59,5 +59,19 @@ $additional_plist_content $plist_launch_screen_name CADisableMinimumFrameDurationOnPhone + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + + + + diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 06095332fa1..0c12f0f0719 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -14,6 +14,7 @@ iphone_lib = [ "tts_ios.mm", "display_layer.mm", "godot_app_delegate.m", + "godot_scene_delegate.m", "godot_view_renderer.mm", "device_metrics.m", "keyboard_input_view.mm", diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h index a211ce2a106..9191a19edfd 100644 --- a/platform/iphone/app_delegate.h +++ b/platform/iphone/app_delegate.h @@ -32,7 +32,9 @@ @class ViewController; -@interface AppDelegate : NSObject +@interface AppDelegate : NSObject + ++ (AppDelegate *)getSingleton; @property(strong, nonatomic) UIWindow *window; @property(strong, class, readonly, nonatomic) ViewController *viewController; diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index 714846191d5..6fafefa7720 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -64,11 +64,37 @@ static ViewController *mainViewController = nil; return mainViewController; } -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Create a full-screen window - CGRect windowBounds = [[UIScreen mainScreen] bounds]; - self.window = [[UIWindow alloc] initWithFrame:windowBounds]; +static AppDelegate *delegate_singleton = nil; ++ (AppDelegate *)getSingleton { + if (!delegate_singleton) { + delegate_singleton = [AppDelegate new]; + } + return delegate_singleton; +} + +- (void)createViewController { + ViewController *viewController = [[ViewController alloc] init]; + viewController.godotView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO; + viewController.godotView.renderingInterval = 1.0 / kRenderingFrequency; + + self.window.rootViewController = viewController; + + // Show the window + [self.window makeKeyAndVisible]; + + mainViewController = viewController; +} + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *window_scene = (UIWindowScene *)scene; + self.window = [[UIWindow alloc] initWithWindowScene:window_scene]; + [self createViewController]; + } +} + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; @@ -83,18 +109,14 @@ static ViewController *mainViewController = nil; return FALSE; } - // WARNING: We must *always* create the GodotView after we have constructed the - // OS with iphone_main. This allows the GodotView to access project settings so - // it can properly initialize the OpenGL context - - ViewController *viewController = [[ViewController alloc] init]; - viewController.godotView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO; - viewController.godotView.renderingInterval = 1.0 / kRenderingFrequency; - - self.window.rootViewController = viewController; - - // Show the window - [self.window makeKeyAndVisible]; + if (@available(iOS 13, tvOS 13, *)) { + // NOP + } else { + // Create a full-screen window + CGRect windowBounds = [[UIScreen mainScreen] bounds]; + self.window = [[UIWindow alloc] initWithFrame:windowBounds]; + [self createViewController]; + } [[NSNotificationCenter defaultCenter] addObserver:self @@ -102,8 +124,6 @@ static ViewController *mainViewController = nil; name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; - mainViewController = viewController; - int sessionCategorySetting = GLOBAL_GET("audio/general/ios/session_category"); // Initialize with default Ambient category. @@ -166,22 +186,42 @@ static ViewController *mainViewController = nil; // if you open the app list without switching to another app or open/close the // notification panel by swiping from the upper part of the screen. +- (void)sceneDidDisconnect:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) { + OSIPhone::get_singleton()->on_focus_out(); +} + - (void)applicationWillResignActive:(UIApplication *)application { OSIPhone::get_singleton()->on_focus_out(); } +- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) { + OSIPhone::get_singleton()->on_focus_out(); +} + - (void)applicationDidBecomeActive:(UIApplication *)application { OSIPhone::get_singleton()->on_focus_in(); } +- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) { + OSIPhone::get_singleton()->on_focus_in(); +} + - (void)applicationDidEnterBackground:(UIApplication *)application { OSIPhone::get_singleton()->on_enter_background(); } +- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) { + OSIPhone::get_singleton()->on_enter_background(); +} + - (void)applicationWillEnterForeground:(UIApplication *)application { OSIPhone::get_singleton()->on_exit_background(); } +- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) { + OSIPhone::get_singleton()->on_exit_background(); +} + - (void)dealloc { self.window = nil; } diff --git a/platform/iphone/godot_app_delegate.m b/platform/iphone/godot_app_delegate.m index 74e8705bc3f..8b174ede807 100644 --- a/platform/iphone/godot_app_delegate.m +++ b/platform/iphone/godot_app_delegate.m @@ -31,6 +31,7 @@ #import "godot_app_delegate.h" #import "app_delegate.h" +#import "godot_scene_delegate.h" @interface GodotApplicalitionDelegate () @@ -46,7 +47,7 @@ static NSMutableArray *services = nil; + (void)load { services = [NSMutableArray new]; - [services addObject:[AppDelegate new]]; + [services addObject:[AppDelegate getSingleton]]; } + (void)addService:(ApplicationDelegateService *)service { @@ -63,15 +64,29 @@ static NSMutableArray *services = nil; - (UIWindow *)window { UIWindow *result = nil; - for (ApplicationDelegateService *service in services) { - if (![service respondsToSelector:_cmd]) { - continue; + if (@available(iOS 13, tvOS 13, *)) { + for (SceneDelegateService *service in [SceneDelegate services]) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + UIWindow *value = [service window]; + + if (value) { + result = value; + } } + } else { + for (ApplicationDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } - UIWindow *value = [service window]; + UIWindow *value = [service window]; - if (value) { - result = value; + if (value) { + result = value; + } } } @@ -456,12 +471,15 @@ static NSMutableArray *services = nil; } } -/* Handled By Info.plist file for now - // MARK: Interface Geometry -- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {} +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0), tvos(13.0)) { + UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; + config.delegateClass = [SceneDelegate class]; + return config; +} -*/ +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions API_AVAILABLE(ios(13.0), tvos(13.0)) { +} @end diff --git a/platform/iphone/godot_scene_delegate.h b/platform/iphone/godot_scene_delegate.h new file mode 100644 index 00000000000..16f47ff01b3 --- /dev/null +++ b/platform/iphone/godot_scene_delegate.h @@ -0,0 +1,42 @@ +/**************************************************************************/ +/* godot_scene_delegate.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#import + +typedef NSObject SceneDelegateService API_AVAILABLE(ios(13.0), tvos(13.0)); + +API_AVAILABLE(ios(13.0), tvos(13.0)) +@interface SceneDelegate : NSObject + +@property(class, readonly, strong) NSArray *services; + ++ (void)addService:(SceneDelegateService *)service; + +@end diff --git a/platform/iphone/godot_scene_delegate.m b/platform/iphone/godot_scene_delegate.m new file mode 100644 index 00000000000..8140256782b --- /dev/null +++ b/platform/iphone/godot_scene_delegate.m @@ -0,0 +1,122 @@ +/**************************************************************************/ +/* godot_scene_delegate.m */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#import "godot_scene_delegate.h" + +#import "app_delegate.h" + +@implementation SceneDelegate + +API_AVAILABLE(ios(13.0), tvos(13.0)) +static NSMutableArray *services = nil; + ++ (NSArray *)services API_AVAILABLE(ios(13.0), tvos(13.0)) { + return services; +} + ++ (void)load { + if (@available(iOS 13, tvOS 13, *)) { + services = [NSMutableArray new]; + [services addObject:[AppDelegate getSingleton]]; + } +} + ++ (void)addService:(SceneDelegateService *)service API_AVAILABLE(ios(13.0), tvos(13.0)) { + if (!services || !service) { + return; + } + [services addObject:service]; +} + +// MARK: Scene + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0), tvos(13.0)) { + for (SceneDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service scene:scene willConnectToSession:session options:connectionOptions]; + } +} + +// MARK: Life-Cycle + +- (void)sceneDidDisconnect:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)) { + for (SceneDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service sceneDidDisconnect:scene]; + } +} + +- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)) { + for (SceneDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service sceneDidBecomeActive:scene]; + } +} + +- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)) { + for (SceneDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service sceneWillResignActive:scene]; + } +} + +- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)) { + for (SceneDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service sceneDidEnterBackground:scene]; + } +} + +- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)) { + for (SceneDelegateService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service sceneWillEnterForeground:scene]; + } +} + +@end