From 7289baae48063306a676b9f7fb881bb084871dbd Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 9 May 2026 13:45:31 +0200 Subject: [PATCH 1/5] Fix iOS game app SDK target to match libs --- .../Binaries/Project/FlaxGame.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj b/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj index 3b8889487..a2337d13c 100644 --- a/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj +++ b/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj @@ -223,7 +223,7 @@ ${PBXResourcesGroup} GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "${HeaderSearchPaths}"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -276,7 +276,7 @@ ${PBXResourcesGroup} GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "${HeaderSearchPaths}"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -302,7 +302,7 @@ ${PBXResourcesGroup} INFOPLIST_KEY_UIStatusBarHidden = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "${UISupportedInterfaceOrientations_iPad}"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "${UISupportedInterfaceOrientations_iPhone}"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -342,7 +342,7 @@ ${PBXResourcesGroup} INFOPLIST_KEY_UIStatusBarHidden = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "${UISupportedInterfaceOrientations_iPad}"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "${UISupportedInterfaceOrientations_iPhone}"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", From 4ce06c8242bb5eea6e40bc9eab668d28c584b5cc Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 9 May 2026 22:32:21 +0200 Subject: [PATCH 2/5] Update iOS to work on the latest devices with iOS 26 --- .../FlaxGame.xcodeproj/project.pbxproj | 2 ++ .../iOS/Binaries/Project/FlaxGame/Info.plist | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 Source/Platforms/iOS/Binaries/Project/FlaxGame/Info.plist diff --git a/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj b/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj index a2337d13c..047dde664 100644 --- a/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj +++ b/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj @@ -293,6 +293,7 @@ ${PBXResourcesGroup} CURRENT_PROJECT_VERSION = ${AppVersion}; DEVELOPMENT_TEAM = ${AppTeamId}; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = FlaxGame/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "${ProjectName}"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -333,6 +334,7 @@ ${PBXResourcesGroup} CURRENT_PROJECT_VERSION = ${AppVersion}; DEVELOPMENT_TEAM = ${AppTeamId}; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = FlaxGame/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "${ProjectName}"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; diff --git a/Source/Platforms/iOS/Binaries/Project/FlaxGame/Info.plist b/Source/Platforms/iOS/Binaries/Project/FlaxGame/Info.plist new file mode 100644 index 000000000..99eb6f55c --- /dev/null +++ b/Source/Platforms/iOS/Binaries/Project/FlaxGame/Info.plist @@ -0,0 +1,21 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + + + + + + From 834cb9411000bf205dde61b7358b136cedf56672 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 11 May 2026 21:35:27 +0200 Subject: [PATCH 3/5] Fix loading engine managed assembly on iOS regression --- Source/Engine/Scripting/Runtime/DotNet.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 0c1901e4b..4d5665d3b 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -2083,10 +2083,23 @@ static MonoAssembly* OnMonoAssemblyLoad(const char* aname) LOG(Info, "Loading C# assembly from path = {0}, exist = {1}", path, FileSystem::FileExists(path)); #endif MonoAssembly* assembly = nullptr; + MonoImageOpenStatus status = MONO_IMAGE_IMAGE_INVALID; if (FileSystem::FileExists(path)) { StringAnsi pathAnsi(path); - assembly = mono_assembly_open(pathAnsi.Get(), nullptr); +#if PLATFORM_IOS + Array data; + File::ReadAllBytes(path, data); + const auto name = path.ToStringAnsi(); + const auto assemblyImage = mono_image_open_from_data_with_name(reinterpret_cast(data.Get()), data.Count(), true, &status, false, name.Get()); + if (assemblyImage) + { + assembly = mono_assembly_load_from_full(assemblyImage, name.Substring(0, name.Length() - 3).Get(), &status, false); + mono_image_close(assemblyImage); + } +#else + assembly = mono_assembly_open(pathAnsi.Get(), &status); +#endif } if (!assembly) { From dcccc4687ddcb328d6d3b9753ae964b7e1a56028 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 11 May 2026 22:27:21 +0200 Subject: [PATCH 4/5] Fix swapchain creation on the latest iOS to run on UI thread --- .../Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp index d270ea89e..0e9ec0ec8 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp @@ -401,7 +401,15 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height) VkBool32 supportsPresent; VALIDATE_VULKAN_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(gpu, _device->PresentQueue->GetFamilyIndex(), _surface, &supportsPresent)); ASSERT(supportsPresent); +#if PLATFORM_IOS + Function func = [this, &device, &swapChainInfo]() + { + VALIDATE_VULKAN_RESULT(vkCreateSwapchainKHR(device, &swapChainInfo, nullptr, &_swapChain)); + }; + iOSPlatform::RunOnUIThread(func, true); +#else VALIDATE_VULKAN_RESULT(vkCreateSwapchainKHR(device, &swapChainInfo, nullptr, &_swapChain)); +#endif // Cache data _width = width; From f83488355df6daa7ea38b7708a8af7932461165a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 13 May 2026 22:33:31 +0200 Subject: [PATCH 5/5] Fix new UIScene flow on the latest iOS --- Source/Engine/Platform/iOS/iOSApp.h | 2 +- Source/Engine/Platform/iOS/iOSPlatform.cpp | 82 ++++++++++++++++++++-- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Platform/iOS/iOSApp.h b/Source/Engine/Platform/iOS/iOSApp.h index bc11f7931..e025bcc6a 100644 --- a/Source/Engine/Platform/iOS/iOSApp.h +++ b/Source/Engine/Platform/iOS/iOSApp.h @@ -23,7 +23,7 @@ FLAXENGINE_API @end FLAXENGINE_API -@interface FlaxAppDelegate : UIResponder +@interface FlaxAppDelegate : UIResponder @property(strong, retain, nonatomic) UIWindow* window; @property(strong, retain, nonatomic) FlaxViewController* viewController; diff --git a/Source/Engine/Platform/iOS/iOSPlatform.cpp b/Source/Engine/Platform/iOS/iOSPlatform.cpp index 18d576133..a6c57c587 100644 --- a/Source/Engine/Platform/iOS/iOSPlatform.cpp +++ b/Source/Engine/Platform/iOS/iOSPlatform.cpp @@ -248,11 +248,13 @@ MessagePipeline MainThreadPipeline; UIThreadPipeline.Run(); } -- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions +- (void)scene:(UIScene*)scene willConnectToSession:(UISceneSession*)session options:(UISceneConnectionOptions*)connectionOptions { + //LOG(Info, "[iOS] willConnectToSession"); + // Create window CGRect frame = [[UIScreen mainScreen] bounds]; - self.window = [[UIWindow alloc] initWithFrame:frame]; + self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene]; // Create view self.view = [[FlaxView alloc] initWithFrame:frame]; @@ -271,10 +273,80 @@ MessagePipeline MainThreadPipeline; [self.viewController setNeedsStatusBarAppearanceUpdate]; MainViewController = self.viewController; - // Create navigation controller - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; - [self.window setRootViewController:navController]; + // Link controller and show window + self.window.rootViewController = MainViewController; [self.window makeKeyAndVisible]; +} + +- (UISceneConfiguration*)application:(UIApplication*)application configurationForConnectingSceneSession:(UISceneSession*)connectingSceneSession options:(UISceneConnectionOptions*)options API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] configurationForConnectingSceneSession"); + UISceneConfiguration* config = [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; + config.delegateClass = [FlaxAppDelegate class]; + return config; +} + +- (void)application:(UIApplication*)application didDiscardSceneSessions:(NSSet*)sceneSessions API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] didDiscardSceneSessions"); +} + +- (void)sceneDidDisconnect:(UIScene*)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] sceneDidDisconnect"); +} + +- (void)sceneDidBecomeActive:(UIScene*)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] sceneDidBecomeActive"); + + // Focus app + HasFocus = true; + if (MainWindow) + { + Function func = []() + { + MainWindow->OnGotFocus(); + }; + iOSPlatform::RunOnMainThread(func); + } +} + +- (void)sceneWillResignActive:(UIScene*)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] sceneWillResignActive"); + + // Defocus app + HasFocus = false; + if (MainWindow) + { + Function func = []() + { + MainWindow->OnLostFocus(); + }; + iOSPlatform::RunOnMainThread(func); + } +} + +- (void)sceneDidEnterBackground:(UIScene*)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] sceneDidEnterBackground"); + + // Pause + IsPaused = true; +} + +- (void)sceneWillEnterForeground:(UIScene*)scene API_AVAILABLE(ios(13.0), tvos(13.0), visionos(1.0)) +{ + LOG(Info, "[iOS] sceneDidEnterBackground"); + + // Resume + IsPaused = false; +} + +- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions +{ + //LOG(Info, "[iOS] didFinishLaunchingWithOptions"); // Create UI thread update callback self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(UIThreadMain)];