Skip to content

Commit 13350bc

Browse files
authored
Migrate iOS app framework to required UIKit scene-based lifecycle (#1503)
* Migrate iOS application framework to required UIKit scene-based lifecycle * Update the Vulkan sub-view to match parent view dimensions on rotation * Add touchscreen input handling to iOS application framework * Update copyright date in iOS info.plist file * Update copyright in new SceneDelegate.h and SceneDelegate.m files
1 parent f9b1603 commit 13350bc

7 files changed

Lines changed: 191 additions & 28 deletions

File tree

app/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2019-2025, Arm Limited and Contributors
1+
# Copyright (c) 2019-2026, Arm Limited and Contributors
22
#
33
# SPDX-License-Identifier: Apache-2.0
44
#
@@ -49,6 +49,8 @@ elseif(IOS)
4949
${CMAKE_CURRENT_SOURCE_DIR}/ios/main.mm
5050
${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.h
5151
${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.m
52+
${CMAKE_CURRENT_SOURCE_DIR}/ios/SceneDelegate.h
53+
${CMAKE_CURRENT_SOURCE_DIR}/ios/SceneDelegate.m
5254
${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.h
5355
${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.mm
5456
)

app/ios/AppDelegate.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2024, Holochip Inc.
1+
/* Copyright (c) 2024-2026, Holochip Inc.
22
*
33
* SPDX-License-Identifier: Apache-2.0
44
*
@@ -25,7 +25,6 @@
2525
#if TARGET_OS_IOS
2626
@interface AppDelegate : UIResponder <UIApplicationDelegate>
2727

28-
@property (strong, nonatomic) UIWindow *window;
2928
#else
3029
@interface AppDelegate : NSResponder <NSApplicationDelegate>
3130

app/ios/AppDelegate.m

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2024, Holochip Inc.
1+
/* Copyright (c) 2024-2026, Holochip Inc.
22
*
33
* SPDX-License-Identifier: Apache-2.0
44
*
@@ -29,27 +29,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
2929
return YES;
3030
}
3131

32-
33-
- (void)applicationWillResignActive:(UIApplication *)application {
34-
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
35-
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
36-
}
37-
38-
39-
- (void)applicationDidEnterBackground:(UIApplication *)application {
40-
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32+
- (void)applicationWillTerminate:(UIApplication *)application {
33+
// Called when the application is about to terminate. Save data if appropriate.
4134
}
4235

43-
44-
- (void)applicationWillEnterForeground:(UIApplication *)application {
45-
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
46-
}
47-
48-
49-
- (void)applicationDidBecomeActive:(UIApplication *)application {
50-
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
51-
}
52-
53-
5436
@end
5537
#endif

app/ios/Info.plist

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
Copyright (c) 2024, Holochip Inc.
3+
Copyright (c) 2024-2026, Holochip Inc.
44
55
SPDX-License-Identifier: Apache-2.0
66
@@ -47,6 +47,25 @@ limitations under the License.
4747
<string>Storyboard</string>
4848
<key>UILaunchStoryboardName</key>
4949
<string>launch</string>
50+
<key>UIApplicationSceneManifest</key>
51+
<dict>
52+
<key>UIApplicationSupportsMultipleScenes</key>
53+
<false/>
54+
<key>UISceneConfigurations</key>
55+
<dict>
56+
<key>UIWindowSceneSessionRoleApplication</key>
57+
<array>
58+
<dict>
59+
<key>UISceneConfigurationName</key>
60+
<string>Default Configuration</string>
61+
<key>UISceneDelegateClassName</key>
62+
<string>SceneDelegate</string>
63+
<key>UISceneStoryboardFile</key>
64+
<string>Storyboard</string>
65+
</dict>
66+
</array>
67+
</dict>
68+
</dict>
5069
<key>CSResourcesFileMapped</key>
5170
<true/>
5271
<key>NSHumanReadableCopyright</key>

app/ios/SceneDelegate.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* Copyright (c) 2026, Stephen Saunders
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 the "License";
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#import <UIKit/UIKit.h>
19+
20+
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
21+
22+
@property (strong, nonatomic) UIWindow *window;
23+
24+
@end
25+

app/ios/SceneDelegate.m

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* Copyright (c) 2026, Stephen Saunders
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 the "License";
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#import "SceneDelegate.h"
19+
#import "ViewController.h"
20+
21+
@interface SceneDelegate ()
22+
23+
@end
24+
25+
@implementation SceneDelegate
26+
27+
28+
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
29+
UIWindowScene *windowScene = (UIWindowScene *)scene;
30+
31+
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
32+
self.window.rootViewController = [[ViewController alloc] init];
33+
34+
[self.window makeKeyAndVisible];
35+
}
36+
37+
- (void)sceneWillEnterForeground:(UIScene *)scene {
38+
// Called as the scene transitions from the background to the foreground.
39+
// Use this method to undo the changes made on entering the background.
40+
}
41+
42+
- (void)sceneDidBecomeActive:(UIScene *)scene {
43+
// Called when the scene has moved from an inactive state to an active state.
44+
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
45+
}
46+
47+
- (void)sceneWillResignActive:(UIScene *)scene {
48+
// Called when the scene will move from an active state to an inactive state.
49+
// This may occur due to temporary interruptions (ex. an incoming phone call).
50+
}
51+
52+
- (void)sceneDidEnterBackground:(UIScene *)scene {
53+
// Called as the scene transitions from the foreground to the background.
54+
// Use this method to save data, release shared resources, and store enough scene-specific state information
55+
// to restore the scene back to its current state.
56+
}
57+
58+
- (void)sceneDidDisconnect:(UIScene *)scene {
59+
// Called as the scene is being released by the system.
60+
// This occurs shortly after the scene enters the background, or when its session is discarded.
61+
// Release any resources associated with this scene that can be re-created the next time the scene connects.
62+
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
63+
}
64+
65+
@end

app/ios/ViewController.mm

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2024, Holochip Inc.
1+
/* Copyright (c) 2024-2026, Holochip Inc.
22
*
33
* SPDX-License-Identifier: Apache-2.0
44
*
@@ -20,6 +20,7 @@
2020
#include "core/platform/entrypoint.hpp"
2121
#include "platform/ios/ios_platform.h"
2222
#include "platform/ios/ios_window.h"
23+
#include "platform/input_events.h"
2324

2425
int platform_main(const vkb::PlatformContext &);
2526

@@ -28,16 +29,16 @@ @interface ViewController(){
2829
std::unique_ptr<vkb::PlatformContext> context;
2930
vkb::IosPlatformContext* _context;
3031
vkb::ExitCode _code;
32+
UITouch* _activeTouch;
3133
}
3234
@property (retain, nonatomic) IBOutlet VulkanView *vulkan_view;
3335

3436
@end
3537

3638
@implementation ViewController
37-
- (void)viewDidLoad {
39+
- (void) viewDidLoad {
3840
[super viewDidLoad];
3941

40-
4142
// Convert incoming args to "C" argc/argv strings
4243
NSArray *args = [[NSProcessInfo processInfo] arguments];
4344
const char** argv = (const char**) alloca(sizeof(char*) * args.count);
@@ -46,6 +47,10 @@ - (void)viewDidLoad {
4647
argv[i] = s.UTF8String;
4748
}
4849

50+
// Allocate and add a Metal-compatible sub-view for Vulkan to use
51+
self.vulkan_view = [[VulkanView alloc] initWithFrame:self.view.bounds];
52+
[self.view addSubview:self.vulkan_view];
53+
4954
self.vulkan_view.contentScaleFactor = UIScreen.mainScreen.nativeScale;
5055

5156
context = create_platform_context((int)args.count, const_cast<char**>(argv));
@@ -58,6 +63,13 @@ - (void)viewDidLoad {
5863
[_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode];
5964
}
6065

66+
- (void) viewDidLayoutSubviews {
67+
[super viewDidLayoutSubviews];
68+
69+
// Update the Vulkan sub-view to match parent view dimensions following rotation events
70+
self.vulkan_view.layer.frame = self.view.bounds;
71+
}
72+
6173
-(void) renderLoop {
6274
if(!_displayLink.isPaused && [UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
6375
if(_code == vkb::ExitCode::Success) {
@@ -73,4 +85,63 @@ -(void) renderLoop {
7385
}
7486
}
7587
}
88+
89+
-(CGPoint) getTouchLocalPoint:(UITouch*) touch {
90+
CGPoint point = [touch locationInView:self.vulkan_view];
91+
point.x *= self.vulkan_view.contentScaleFactor;
92+
point.y *= self.vulkan_view.contentScaleFactor;
93+
return point;
94+
}
95+
96+
// Handle touch events for selection and dragging within the display and GUI overlay
97+
-(void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) theEvent {
98+
if (_activeTouch == nil) {
99+
_activeTouch = [touches anyObject];
100+
101+
auto point = [self getTouchLocalPoint:_activeTouch];
102+
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
103+
0, 1,
104+
vkb::TouchAction::Down,
105+
static_cast<float>(point.x),
106+
static_cast<float>(point.y)});
107+
}
108+
}
109+
110+
-(void) touchesMoved:(NSSet*) touches withEvent:(UIEvent*) theEvent {
111+
if (_activeTouch && [touches containsObject:_activeTouch]) {
112+
auto point = [self getTouchLocalPoint:_activeTouch];
113+
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
114+
0, 1,
115+
vkb::TouchAction::Move,
116+
static_cast<float>(point.x),
117+
static_cast<float>(point.y)});
118+
}
119+
}
120+
121+
-(void) touchesEnded:(NSSet*) touches withEvent:(UIEvent*) theEvent {
122+
if (_activeTouch && [touches containsObject:_activeTouch]) {
123+
auto point = [self getTouchLocalPoint:_activeTouch];
124+
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
125+
0, 1,
126+
vkb::TouchAction::Up,
127+
static_cast<float>(point.x),
128+
static_cast<float>(point.y)});
129+
130+
_activeTouch = nil;
131+
}
132+
}
133+
134+
-(void) touchesCancelled:(NSSet*) touches withEvent:(UIEvent*) theEvent {
135+
if (_activeTouch && [touches containsObject:_activeTouch]) {
136+
auto point = [self getTouchLocalPoint:_activeTouch];
137+
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
138+
0, 1,
139+
vkb::TouchAction::Cancel,
140+
static_cast<float>(point.x),
141+
static_cast<float>(point.y)});
142+
143+
_activeTouch = nil;
144+
}
145+
}
146+
76147
@end

0 commit comments

Comments
 (0)