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 3d2ae6b52b92..782d1448dbb5 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/ios/SCsub b/platform/ios/SCsub
index d16dcb1a95a3..eef173e163c1 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -72,6 +72,7 @@ ios_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/ios/app_delegate.h b/platform/ios/app_delegate.h
index d8310792aae5..9191a19edfd1 100644
--- a/platform/ios/app_delegate.h
+++ b/platform/ios/app_delegate.h
@@ -32,14 +32,9 @@
@class ViewController;
-// FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented again,
-// so it can't be done with compilation time branching.
-//#if defined(GLES3_ENABLED)
-//@interface AppDelegate : NSObject {
-//#endif
-//#if defined(VULKAN_ENABLED)
-@interface AppDelegate : NSObject
-//#endif
+@interface AppDelegate : NSObject
+
++ (AppDelegate *)getSingleton;
@property(strong, nonatomic) UIWindow *window;
@property(strong, class, readonly, nonatomic) ViewController *viewController;
diff --git a/platform/ios/app_delegate.mm b/platform/ios/app_delegate.mm
index 37d269643488..40d45a8c4213 100644
--- a/platform/ios/app_delegate.mm
+++ b/platform/ios/app_delegate.mm
@@ -66,24 +66,16 @@ + (ViewController *)viewController {
return mainViewController;
}
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // TODO: might be required to make an early return, so app wouldn't crash because of timeout.
- // TODO: logo screen is not displayed while shaders are compiling
- // DummyViewController(Splash/LoadingViewController) -> setup -> GodotViewController
-
- CGRect windowBounds = [[UIScreen mainScreen] bounds];
-
- // Create a full-screen window
- self.window = [[UIWindow alloc] initWithFrame:windowBounds];
+static AppDelegate *delegate_singleton = nil;
- int err = ios_main(gargc, gargv);
-
- if (err != 0) {
- // bail, things did not go very well for us, should probably output a message on screen with our error code...
- exit(0);
- return NO;
++ (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;
@@ -93,14 +85,41 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
// 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)) {
+ 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 {
+ int err = ios_main(gargc, gargv);
+
+ if (err != 0) {
+ // bail, things did not go very well for us, should probably output a message on screen with our error code...
+ exit(0);
+ return NO;
+ }
+
+ if (@available(iOS 13, tvOS 13, visionOS 1, *)) {
+ // NOP
+ } else {
+ // Create a full-screen window
+ CGRect windowBounds = [[UIScreen mainScreen] bounds];
+ self.window = [[UIWindow alloc] initWithFrame:windowBounds];
+ [self createViewController];
+ }
+
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onAudioInterruption:)
name:AVAudioSessionInterruptionNotification
object:[AVAudioSession sharedInstance]];
- mainViewController = viewController;
-
int sessionCategorySetting = GLOBAL_GET("audio/general/ios/session_category");
// Initialize with default Ambient category.
@@ -163,22 +182,42 @@ - (void)applicationWillTerminate:(UIApplication *)application {
// 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)) {
+ OS_IOS::get_singleton()->on_focus_out();
+}
+
- (void)applicationWillResignActive:(UIApplication *)application {
OS_IOS::get_singleton()->on_focus_out();
}
+- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
+ OS_IOS::get_singleton()->on_focus_out();
+}
+
- (void)applicationDidBecomeActive:(UIApplication *)application {
OS_IOS::get_singleton()->on_focus_in();
}
+- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
+ OS_IOS::get_singleton()->on_focus_in();
+}
+
- (void)applicationDidEnterBackground:(UIApplication *)application {
OS_IOS::get_singleton()->on_enter_background();
}
+- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
+ OS_IOS::get_singleton()->on_enter_background();
+}
+
- (void)applicationWillEnterForeground:(UIApplication *)application {
OS_IOS::get_singleton()->on_exit_background();
}
+- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
+ OS_IOS::get_singleton()->on_exit_background();
+}
+
- (void)dealloc {
self.window = nil;
}
diff --git a/platform/ios/godot_app_delegate.m b/platform/ios/godot_app_delegate.m
index 53e53cd0c658..6ce9aea53c97 100644
--- a/platform/ios/godot_app_delegate.m
+++ b/platform/ios/godot_app_delegate.m
@@ -31,6 +31,7 @@
#import "godot_app_delegate.h"
#import "app_delegate.h"
+#import "godot_scene_delegate.h"
@interface GodotApplicationDelegate ()
@@ -46,7 +47,7 @@ @implementation GodotApplicationDelegate
+ (void)load {
services = [NSMutableArray new];
- [services addObject:[AppDelegate new]];
+ [services addObject:[AppDelegate getSingleton]];
}
+ (void)addService:(ApplicationDelegateService *)service {
@@ -63,15 +64,29 @@ + (void)addService:(ApplicationDelegateService *)service {
- (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 @@ - (void)application:(UIApplication *)application userDidAcceptCloudKitShareWithM
}
}
-/* 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/ios/godot_scene_delegate.h b/platform/ios/godot_scene_delegate.h
new file mode 100644
index 000000000000..16f47ff01b31
--- /dev/null
+++ b/platform/ios/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/ios/godot_scene_delegate.m b/platform/ios/godot_scene_delegate.m
new file mode 100644
index 000000000000..f6419e712a12
--- /dev/null
+++ b/platform/ios/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, visionOS 1, *)) {
+ 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