Skip to content

Commit 038f593

Browse files
committed
[Apple embedded] Adopt SwiftUI lifecycle for Apple embedded platforms
- Introduces a SCons builder for Swift files - Increases the minimum deployment targets to iOS 14.0, and visionOS 26.0. - Replaces manually UIWindow management by a SwiftUI instantiated app.
1 parent 3bf0f77 commit 038f593

29 files changed

+346
-196
lines changed

drivers/apple_embedded/SCsub

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
#!/usr/bin/env python
22
from misc.utility.scons_hints import *
33

4+
from SCons.Script import Glob
5+
6+
from platform_methods import setup_swift_builder
7+
48
Import("env")
59

610
env_apple_embedded = env.Clone()
711

812
# Enable module support
913
env_apple_embedded.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
1014

15+
# Configure Swift builder
16+
apple_platform = env["APPLE_PLATFORM"]
17+
sdk_path = env["APPLE_SDK_PATH"]
18+
current_path = Dir(".").abspath
19+
bridging_header_filename = "bridging_header_apple_embedded.h"
20+
swift_files = Glob("*.swift")
21+
swift_file_names = list(map(lambda f: f.name, swift_files))
22+
setup_swift_builder(
23+
env_apple_embedded, apple_platform, sdk_path, current_path, bridging_header_filename, swift_file_names
24+
)
25+
1126
# Use bundled Vulkan headers
1227
vulkan_dir = "#thirdparty/vulkan"
1328
env_apple_embedded.Prepend(CPPPATH=[vulkan_dir, vulkan_dir + "/include"])
1429

1530
# Driver source files
16-
env_apple_embedded.add_source_files(env.drivers_sources, "*.mm")
31+
env_apple_embedded.add_source_files(env_apple_embedded.drivers_sources, "*.mm")
32+
env_apple_embedded.add_source_files(env_apple_embedded.drivers_sources, "*.swift")

drivers/apple_embedded/app.swift

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**************************************************************************/
2+
/* app.swift */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
import SwiftUI
32+
import UIKit
33+
34+
struct GodotSwiftUIViewController: UIViewControllerRepresentable {
35+
36+
func makeUIViewController(context: Context) -> GDTViewController {
37+
let viewController = GDTViewController()
38+
GDTAppDelegateService.viewController = viewController
39+
return viewController
40+
}
41+
42+
func updateUIViewController(_ uiViewController: GDTViewController, context: Context) {
43+
// NOOP
44+
}
45+
46+
}
47+
48+
@main
49+
struct SwiftUIApp: App {
50+
@UIApplicationDelegateAdaptor(GDTApplicationDelegate.self) var appDelegate
51+
@Environment(\.scenePhase) private var scenePhase
52+
53+
var body: some Scene {
54+
WindowGroup {
55+
GodotSwiftUIViewController()
56+
.ignoresSafeArea()
57+
// UIViewControllerRepresentable does not call viewWillDisappear() nor viewDidDisappear() when
58+
// backgrounding the app, or closing the app's main window, update the renderer here.
59+
.onChange(of: scenePhase) { phase in
60+
// For some reason UIViewControllerRepresentable is not calling viewWillDisappear()
61+
// nor viewDidDisappear when closing the app's main window, call it here so we
62+
// stop the renderer.
63+
switch phase {
64+
case .active:
65+
print("GodotSwiftUIViewController scene active")
66+
GDTAppDelegateService.viewController?.godotView.startRendering()
67+
case .inactive:
68+
print("GodotSwiftUIViewController scene inactive")
69+
GDTAppDelegateService.viewController?.godotView.stopRendering()
70+
case .background:
71+
print("GodotSwiftUIViewController scene backgrounded")
72+
GDTAppDelegateService.viewController?.godotView.stopRendering()
73+
@unknown default:
74+
print("unknown default")
75+
}
76+
}
77+
}
78+
}
79+
}

drivers/apple_embedded/app_delegate_service.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636

3737
@interface GDTAppDelegateService : NSObject <UIApplicationDelegate>
3838

39-
@property(strong, nonatomic) UIWindow *window;
40-
@property(strong, class, readonly, nonatomic) GDTViewController *viewController;
39+
@property(strong, class, nonatomic) GDTViewController *viewController;
4140

4241
@end

drivers/apple_embedded/app_delegate_service.mm

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
#import "app_delegate_service.h"
3232

3333
#import "godot_view_apple_embedded.h"
34+
#import "godot_view_controller.h"
3435
#import "os_apple_embedded.h"
35-
#import "view_controller.h"
3636

3737
#include "core/config/project_settings.h"
3838
#import "drivers/coreaudio/audio_driver_coreaudio.h"
@@ -41,10 +41,8 @@
4141
#import <AVFoundation/AVFoundation.h>
4242
#import <AudioToolbox/AudioServices.h>
4343

44-
#define kRenderingFrequency 60
45-
46-
extern int gargc;
47-
extern char **gargv;
44+
int gargc;
45+
char **gargv;
4846

4947
extern int apple_embedded_main(int, char **);
5048
extern void apple_embedded_finish();
@@ -66,18 +64,23 @@ + (GDTViewController *)viewController {
6664
return mainViewController;
6765
}
6866

67+
+ (void)setViewController:(GDTViewController *)viewController {
68+
mainViewController = viewController;
69+
}
70+
6971
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
7072
// TODO: might be required to make an early return, so app wouldn't crash because of timeout.
7173
// TODO: logo screen is not displayed while shaders are compiling
7274
// DummyViewController(Splash/LoadingViewController) -> setup -> GodotViewController
7375

74-
#if !defined(VISIONOS_ENABLED)
75-
// Create a full-screen window
76-
CGRect windowBounds = [[UIScreen mainScreen] bounds];
77-
self.window = [[UIWindow alloc] initWithFrame:windowBounds];
78-
#else
79-
self.window = [[UIWindow alloc] init];
80-
#endif
76+
// Fetch the command-line arguments from NSProcessInfo
77+
NSArray *arguments = [[NSProcessInfo processInfo] arguments];
78+
gargc = (int)[arguments count];
79+
gargv = (char **)malloc(sizeof(char *) * gargc);
80+
for (int i = 0; i < gargc; i++) {
81+
NSString *arg = arguments[i];
82+
gargv[i] = strdup([arg UTF8String]);
83+
}
8184

8285
int err = apple_embedded_main(gargc, gargv);
8386

@@ -87,23 +90,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
8790
return NO;
8891
}
8992

90-
GDTViewController *viewController = [[GDTViewController alloc] init];
91-
viewController.godotView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO;
92-
viewController.godotView.renderingInterval = 1.0 / kRenderingFrequency;
93-
94-
self.window.rootViewController = viewController;
95-
96-
// Show the window
97-
[self.window makeKeyAndVisible];
98-
9993
[[NSNotificationCenter defaultCenter]
10094
addObserver:self
10195
selector:@selector(onAudioInterruption:)
10296
name:AVAudioSessionInterruptionNotification
10397
object:[AVAudioSession sharedInstance]];
10498

105-
mainViewController = viewController;
106-
10799
int sessionCategorySetting = GLOBAL_GET("audio/general/ios/session_category");
108100

109101
// Initialize with default Ambient category.

drivers/apple_embedded/apple_embedded.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#import "apple_embedded.h"
3232

3333
#import "app_delegate_service.h"
34-
#import "view_controller.h"
34+
#import "godot_view_controller.h"
3535

3636
#import <CoreHaptics/CoreHaptics.h>
3737
#import <UIKit/UIKit.h>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**************************************************************************/
2+
/* bridging_header_apple_embedded.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#pragma once
32+
33+
#import "app_delegate_service.h"
34+
#import "godot_app_delegate.h"
35+
#import "godot_view_apple_embedded.h"
36+
#import "godot_view_controller.h"

drivers/apple_embedded/display_server_apple_embedded.mm

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232

3333
#import "app_delegate_service.h"
3434
#import "apple_embedded.h"
35+
#import "godot_keyboard_input_view.h"
3536
#import "godot_view_apple_embedded.h"
37+
#import "godot_view_controller.h"
3638
#import "key_mapping_apple_embedded.h"
37-
#import "keyboard_input_view.h"
3839
#import "os_apple_embedded.h"
3940
#import "tts_apple_embedded.h"
40-
#import "view_controller.h"
4141

4242
#include "core/config/project_settings.h"
4343
#include "core/io/file_access_pack.h"
@@ -612,9 +612,8 @@
612612
}
613613

614614
Size2i DisplayServerAppleEmbedded::window_get_size(WindowID p_window) const {
615-
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
616-
CGRect windowBounds = appDelegate.window.bounds;
617-
return Size2i(windowBounds.size.width, windowBounds.size.height) * screen_get_max_scale();
615+
CGRect viewBounds = GDTAppDelegateService.viewController.view.bounds;
616+
return Size2i(viewBounds.size.width, viewBounds.size.height) * screen_get_max_scale();
618617
}
619618

620619
Size2i DisplayServerAppleEmbedded::window_get_size_with_decorations(WindowID p_window) const {

drivers/apple_embedded/godot_app_delegate.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#import "godot_app_delegate.h"
3232

3333
#import "app_delegate_service.h"
34+
#include "core/typedefs.h"
3435

3536
@implementation GDTApplicationDelegate
3637

@@ -120,6 +121,9 @@ - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<
120121

121122
// MARK: Life-Cycle
122123

124+
// UIApplication lifecycle has become deprecated in favor of UIScene lifecycle
125+
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations")
126+
123127
- (void)applicationDidBecomeActive:(UIApplication *)application {
124128
for (GDTAppDelegateServiceProtocol *service in services) {
125129
if (![service respondsToSelector:_cmd]) {
@@ -461,3 +465,5 @@ - (UIInterfaceOrientationMask)application:(UIApplication *)application supported
461465
*/
462466

463467
@end
468+
469+
GODOT_CLANG_WARNING_POP

drivers/apple_embedded/keyboard_input_view.h renamed to drivers/apple_embedded/godot_keyboard_input_view.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**************************************************************************/
2-
/* keyboard_input_view.h */
2+
/* godot_keyboard_input_view.h */
33
/**************************************************************************/
44
/* This file is part of: */
55
/* GODOT ENGINE */

drivers/apple_embedded/keyboard_input_view.mm renamed to drivers/apple_embedded/godot_keyboard_input_view.mm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**************************************************************************/
2-
/* keyboard_input_view.mm */
2+
/* godot_keyboard_input_view.mm */
33
/**************************************************************************/
44
/* This file is part of: */
55
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
2828
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
2929
/**************************************************************************/
3030

31-
#import "keyboard_input_view.h"
31+
#import "godot_keyboard_input_view.h"
3232

3333
#import "display_server_apple_embedded.h"
3434
#import "os_apple_embedded.h"

0 commit comments

Comments
 (0)