Merge pull request #116395 from bruvzg/ios_sc

[iOS] Add UIScene lifecycle events.
This commit is contained in:
Rémi Verschelde 2026-02-20 11:16:44 +01:00
commit db77a462b4
No known key found for this signature in database
GPG key ID: C3336907360768E1
6 changed files with 94 additions and 30 deletions

View file

@ -48,32 +48,11 @@ struct GodotSwiftUIViewController: UIViewControllerRepresentable {
@main
struct SwiftUIApp: App {
@UIApplicationDelegateAdaptor(GDTApplicationDelegate.self) var appDelegate
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
GodotSwiftUIViewController()
.ignoresSafeArea()
// UIViewControllerRepresentable does not call viewWillDisappear() nor viewDidDisappear() when
// backgrounding the app, or closing the app's main window, update the renderer here.
.onChange(of: scenePhase) { phase in
// For some reason UIViewControllerRepresentable is not calling viewWillDisappear()
// nor viewDidDisappear when closing the app's main window, call it here so we
// stop the renderer.
switch phase {
case .active:
print("GodotSwiftUIViewController scene active")
GDTAppDelegateService.viewController?.godotView.startRendering()
case .inactive:
print("GodotSwiftUIViewController scene inactive")
GDTAppDelegateService.viewController?.godotView.stopRendering()
case .background:
print("GodotSwiftUIViewController scene backgrounded")
GDTAppDelegateService.viewController?.godotView.stopRendering()
@unknown default:
print("unknown default")
}
}
}
}
}

View file

@ -34,7 +34,7 @@
@class GDTViewController;
@interface GDTAppDelegateService : NSObject <UIApplicationDelegate>
@interface GDTAppDelegateService : NSObject <UIApplicationDelegate, UIWindowSceneDelegate>
@property(strong, class, nonatomic) GDTViewController *viewController;

View file

@ -159,6 +159,26 @@ static GDTViewController *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)) {
OS_AppleEmbedded::get_singleton()->on_focus_out();
}
- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
OS_AppleEmbedded::get_singleton()->on_focus_out();
}
- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
OS_AppleEmbedded::get_singleton()->on_focus_in();
}
- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
OS_AppleEmbedded::get_singleton()->on_enter_background();
}
- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
OS_AppleEmbedded::get_singleton()->on_exit_background();
}
- (void)applicationWillResignActive:(UIApplication *)application {
OS_AppleEmbedded::get_singleton()->on_focus_out();
}

View file

@ -32,9 +32,9 @@
#import <UIKit/UIKit.h>
typedef NSObject<UIApplicationDelegate> GDTAppDelegateServiceProtocol;
typedef NSObject<UIApplicationDelegate, UIWindowSceneDelegate> GDTAppDelegateServiceProtocol;
@interface GDTApplicationDelegate : NSObject <UIApplicationDelegate>
@interface GDTApplicationDelegate : NSObject <UIApplicationDelegate, UIWindowSceneDelegate>
@property(class, readonly, strong) NSArray<GDTAppDelegateServiceProtocol *> *services;

View file

@ -109,18 +109,69 @@ static NSMutableArray<GDTAppDelegateServiceProtocol *> *services = nil;
return result;
}
/* Can be handled by Info.plist. Not yet supported by Godot.
// MARK: Scene
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {}
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
config.delegateClass = [GDTApplicationDelegate class];
return config;
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {}
*/
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
}
// MARK: Life-Cycle
- (void)sceneDidDisconnect:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
for (GDTAppDelegateServiceProtocol *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service sceneDidDisconnect:scene];
}
}
- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
for (GDTAppDelegateServiceProtocol *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service sceneDidBecomeActive:scene];
}
}
- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
for (GDTAppDelegateServiceProtocol *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service sceneWillResignActive:scene];
}
}
- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
for (GDTAppDelegateServiceProtocol *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service sceneDidEnterBackground:scene];
}
}
- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) {
for (GDTAppDelegateServiceProtocol *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service sceneWillEnterForeground:scene];
}
}
// UIApplication lifecycle has become deprecated in favor of UIScene lifecycle
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations")

View file

@ -59,5 +59,19 @@
$additional_plist_content
$plist_launch_screen_name
<key>CADisableMinimumFrameDurationOnPhone</key><true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key><false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>