mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
iOS: Initial attempt at switching to SceneDelegate (UIScene)
Fixes #20884
This commit is contained in:
+3
-1
@@ -1340,6 +1340,8 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
ios/main.mm
|
||||
ios/AppDelegate.mm
|
||||
ios/AppDelegate.h
|
||||
ios/SceneDelegate.mm
|
||||
ios/SceneDelegate.h
|
||||
ios/DisplayManager.h
|
||||
ios/DisplayManager.mm
|
||||
ios/Controls.h
|
||||
@@ -2964,7 +2966,7 @@ endif()
|
||||
# packaging and code signing
|
||||
if(IOS AND NOT LIBRETRO)
|
||||
if(IOS_APP_STORE)
|
||||
set(DEPLOYMENT_TARGET 12.0)
|
||||
set(DEPLOYMENT_TARGET 13.0)
|
||||
else()
|
||||
set(DEPLOYMENT_TARGET 11.0)
|
||||
endif()
|
||||
|
||||
+1
-1
@@ -1531,7 +1531,7 @@ void LaunchBuyGold(ScreenManager *screenManager) {
|
||||
screenManager->push(new IAPScreen());
|
||||
} else {
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://apps.apple.com/us/app/ppsspp-gold-psp-emulator/id6502287918");
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/buygold_ios");
|
||||
#elif PPSSPP_PLATFORM(ANDROID)
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "market://details?id=org.ppsspp.ppssppgold");
|
||||
#else
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# PPSSPP platform flags
|
||||
set(MOBILE_DEVICE ON)
|
||||
set(USING_GLES2 ON)
|
||||
set(IPHONEOS_DEPLOYMENT_TARGET 12.0)
|
||||
set(IPHONEOS_DEPLOYMENT_TARGET 13.0)
|
||||
add_definitions(
|
||||
-DGL_ETC1_RGB8_OES=0
|
||||
-U__STRICT_ANSI__
|
||||
|
||||
+1
-2
@@ -8,8 +8,7 @@
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
@property (strong, nonatomic) UIScreen *screen;
|
||||
|
||||
@property (strong, nonatomic) id<PPSSPPViewController> viewController;
|
||||
@property (nonatomic, strong) NSDictionary *launchOptions;
|
||||
|
||||
- (void)restart:(const char *)args;
|
||||
- (BOOL)launchPPSSPP:(int)argc argv:(char**)argv;
|
||||
|
||||
+16
-82
@@ -1,7 +1,5 @@
|
||||
#import "AppDelegate.h"
|
||||
#import "ViewControllerCommon.h"
|
||||
#import "ViewController.h"
|
||||
#import "ViewControllerMetal.h"
|
||||
#import "SceneDelegate.h"
|
||||
#import "iOSCoreAudio.h"
|
||||
#import "Common/System/System.h"
|
||||
#import "Common/System/NativeApp.h"
|
||||
@@ -11,6 +9,12 @@
|
||||
#import "IAPManager.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
// TODO: Unfortunate hack to force link SceneDelegate class.
|
||||
// This is necessary because otherwise classes from static libraries aren't loaded.
|
||||
// We should move all the iOS code into the main binary directly to avoid this problem.
|
||||
__attribute__((used)) static Class _forceLinkSceneDelegate = [SceneDelegate class];
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
@@ -77,49 +81,21 @@
|
||||
}
|
||||
|
||||
-(BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
int argc = 1;
|
||||
char *argv[5]{};
|
||||
NSURL *nsUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
|
||||
|
||||
if (nsUrl != nullptr && nsUrl.isFileURL) {
|
||||
NSString *nsString = nsUrl.path;
|
||||
const char *string = nsString.UTF8String;
|
||||
argv[argc++] = (char*)string;
|
||||
self.launchOptions = launchOptions;
|
||||
// Make sure SceneDelegate class is loaded
|
||||
Class cls = objc_getClass("SceneDelegate");
|
||||
if (!cls) {
|
||||
NSLog(@"⚠️ SceneDelegate not found via objc_getClass");
|
||||
} else {
|
||||
NSLog(@"✅ SceneDelegate loaded via objc_getClass");
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMediaServicesWereReset:) name:AVAudioSessionMediaServicesWereResetNotification object:nil];
|
||||
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
[IAPManager sharedIAPManager]; // Kick off the IAPManager early.
|
||||
#endif // IOS_APP_STORE
|
||||
|
||||
return [self launchPPSSPP:argc argv:argv];
|
||||
}
|
||||
|
||||
- (BOOL)launchPPSSPP:(int)argc argv:(char**)argv;
|
||||
{
|
||||
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
|
||||
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"];
|
||||
NativeInit(argc, (const char**)argv, documentsPath.UTF8String, bundlePath.UTF8String, NULL);
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
|
||||
// Choose viewcontroller depending on backend.
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
|
||||
PPSSPPViewControllerMetal *vc = [[PPSSPPViewControllerMetal alloc] init];
|
||||
|
||||
self.viewController = vc;
|
||||
self.window.rootViewController = vc;
|
||||
|
||||
} else {
|
||||
PPSSPPViewControllerGL *vc = [[PPSSPPViewControllerGL alloc] init];
|
||||
// Here we can switch viewcontroller depending on backend.
|
||||
self.viewController = vc;
|
||||
self.window.rootViewController = vc;
|
||||
}
|
||||
|
||||
[self.window makeKeyAndVisible];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMediaServicesWereReset:) name:AVAudioSessionMediaServicesWereResetNotification object:nil];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -128,49 +104,7 @@
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)restart:(const char*)restartArgs {
|
||||
INFO_LOG(Log::G3D, "Restart requested: %s", restartArgs);
|
||||
[self.viewController willResignActive];
|
||||
[self.viewController shutdown];
|
||||
self.window.rootViewController = nil;
|
||||
self.viewController = nil;
|
||||
|
||||
// App was requested to restart, probably.
|
||||
INFO_LOG(Log::G3D, "viewController nilled");
|
||||
|
||||
NativeShutdown();
|
||||
|
||||
// TODO: Ignoring the command line for now.
|
||||
// Hoping that overwriting the viewController works as expected...
|
||||
[self launchPPSSPP:0 argv:nullptr];
|
||||
[self.viewController didBecomeActive];
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
INFO_LOG(Log::G3D, "willResignActive");
|
||||
|
||||
[self.viewController willResignActive];
|
||||
|
||||
if (g_Config.bEnableSound) {
|
||||
iOSCoreAudioShutdown();
|
||||
}
|
||||
|
||||
System_PostUIMessage(UIMessage::LOST_FOCUS);
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
INFO_LOG(Log::G3D, "didBecomeActive");
|
||||
if (g_Config.bEnableSound) {
|
||||
iOSCoreAudioInit();
|
||||
}
|
||||
|
||||
System_PostUIMessage(UIMessage::GOT_FOCUS);
|
||||
[self.viewController didBecomeActive];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||
// Seems like a bad idea.
|
||||
// exit(0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -215,4 +215,12 @@ static bool SafeStringEqual(NSString *a, NSString *b) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)productsRequest:(nonnull SKProductsRequest *)request didReceiveResponse:(nonnull SKProductsResponse *)response {
|
||||
NSLog(@"Ignoring [productsRequest]");
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
|
||||
NSLog(@"Ignoring [paymentQueue]");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -206,5 +206,20 @@
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>SceneDelegate</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// SceneDelegate.h
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow * window;
|
||||
@property (strong, nonatomic) UIViewController *viewController;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,119 @@
|
||||
// SceneDelegate.mm
|
||||
|
||||
#import "SceneDelegate.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "iOSCoreAudio.h"
|
||||
#import "ViewControllerCommon.h"
|
||||
#import "ViewController.h"
|
||||
#import "ViewControllerMetal.h"
|
||||
#import "Common/System/NativeApp.h"
|
||||
#import "Common/System/System.h"
|
||||
#import "Core/System.h"
|
||||
#import "Core/Config.h"
|
||||
#import "Common/Log.h"
|
||||
#import "IAPManager.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@implementation SceneDelegate
|
||||
|
||||
+ (void)load {
|
||||
NSLog(@"✅ SceneDelegate class was loaded!");
|
||||
}
|
||||
|
||||
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
|
||||
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if (self.window) {
|
||||
NSLog(@"✅ Window already exists, not creating again!");
|
||||
return;
|
||||
}
|
||||
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
NSDictionary *launchOptions = appDelegate.launchOptions;
|
||||
|
||||
int argc = 1;
|
||||
char *argv[5]{};
|
||||
NSURL *nsUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
|
||||
|
||||
if (nsUrl != nullptr && nsUrl.isFileURL) {
|
||||
NSString *nsString = nsUrl.path;
|
||||
const char *string = nsString.UTF8String;
|
||||
argv[argc++] = (char*)string;
|
||||
}
|
||||
|
||||
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
|
||||
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"];
|
||||
NativeInit(argc, (const char**)argv, documentsPath.UTF8String, bundlePath.UTF8String, NULL);
|
||||
|
||||
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
// self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
|
||||
// Choose viewcontroller depending on backend.
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
|
||||
PPSSPPViewControllerMetal *vc = [[PPSSPPViewControllerMetal alloc] init];
|
||||
|
||||
self.viewController = vc;
|
||||
self.window.rootViewController = vc;
|
||||
|
||||
} else {
|
||||
PPSSPPViewControllerGL *vc = [[PPSSPPViewControllerGL alloc] init];
|
||||
// Here we can switch viewcontroller depending on backend.
|
||||
self.viewController = vc;
|
||||
self.window.rootViewController = vc;
|
||||
}
|
||||
|
||||
[self.window makeKeyAndVisible];
|
||||
}
|
||||
|
||||
- (void)restart:(const char*)restartArgs {
|
||||
INFO_LOG(Log::G3D, "SceneDelegate: Restart requested: %s", restartArgs);
|
||||
|
||||
// Notify current view controller
|
||||
[self.viewController willResignActive];
|
||||
[self.viewController shutdown];
|
||||
|
||||
// Remove the current root view controller
|
||||
self.window.rootViewController = nil;
|
||||
self.viewController = nil;
|
||||
|
||||
INFO_LOG(Log::G3D, "SceneDelegate: viewController nilled");
|
||||
|
||||
// Shut down native systems
|
||||
NativeShutdown();
|
||||
|
||||
// Launch a fresh instance
|
||||
[self launchPPSSPP:0 argv:nullptr];
|
||||
|
||||
// Notify new view controller
|
||||
[self.viewController didBecomeActive];
|
||||
}
|
||||
|
||||
- (void)sceneWillResignActive:(UIScene *)scene {
|
||||
INFO_LOG(Log::G3D, "sceneWillResignActive");
|
||||
|
||||
[self.viewController willResignActive];
|
||||
|
||||
if (g_Config.bEnableSound) {
|
||||
iOSCoreAudioShutdown();
|
||||
}
|
||||
|
||||
System_PostUIMessage(UIMessage::LOST_FOCUS);
|
||||
}
|
||||
|
||||
- (void)sceneDidBecomeActive:(UIScene *)scene {
|
||||
INFO_LOG(Log::G3D, "sceneDidBecomeActive");
|
||||
|
||||
if (g_Config.bEnableSound) {
|
||||
iOSCoreAudioInit();
|
||||
}
|
||||
|
||||
System_PostUIMessage(UIMessage::GOT_FOCUS);
|
||||
|
||||
[self.viewController didBecomeActive];
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user