diff --git a/CMakeLists.txt b/CMakeLists.txt index 241b6c9e15..3712b4059e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2989,7 +2989,6 @@ if(IOS AND NOT LIBRETRO) target_link_libraries(${TargetBin} "${CMAKE_CURRENT_SOURCE_DIR}/ios/MoltenVK/MoltenVK.xcframework/ios-arm64/libMoltenVK.a" ) - # https://stackoverflow.com/questions/40664125/cmake-and-code-signing-in-xcode-8-for-ios-projects set_target_properties(${TargetBin} PROPERTIES XCODE_GENERATE_SCHEME YES # Avoid the scheme bloat in XCode by only setting it to YES for this target. @@ -2999,6 +2998,7 @@ if(IOS AND NOT LIBRETRO) XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${BUNDLE_IDENTIFIER} XCODE_ATTRIBUTE_PRODUCT_NAME ${PRODUCT_NAME} XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${ICON_NAME} + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME "" BUILD_WITH_INSTALL_RPATH YES MACOSX_BUNDLE_INFO_PLIST ${BUNDLE_PLIST} # Some sources say we should generate the PLIST. There's stuff in it that diff --git a/Common/File/PathBrowser.cpp b/Common/File/PathBrowser.cpp index bfef052d2f..a7798db570 100644 --- a/Common/File/PathBrowser.cpp +++ b/Common/File/PathBrowser.cpp @@ -129,7 +129,7 @@ void PathBrowser::SetPath(const Path &path) { } void PathBrowser::RestrictToRoot(const Path &root) { - INFO_LOG(Log::IO, "Restricting to root: %s", root.c_str()); + VERBOSE_LOG(Log::IO, "Restricting to root: %s", root.c_str()); restrictedRoot_ = root; } diff --git a/Core/Config.cpp b/Core/Config.cpp index b4d8f8498b..e0a917c032 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1579,7 +1579,7 @@ void Config::DismissUpgrade() { // The GUID part changes on each launch. bool TryUpdateSavedPath(Path *path) { #if PPSSPP_PLATFORM(IOS) - INFO_LOG(Log::Loader, "Original path: %s", path->c_str()); + // DEBUG_LOG(Log::Loader, "Original path: %s", path->c_str()); std::string pathStr = path->ToString(); const std::string_view applicationRoot = "/var/mobile/Containers/Data/Application/"; diff --git a/Core/Util/RecentFiles.cpp b/Core/Util/RecentFiles.cpp index 9070bd5353..7075723db0 100644 --- a/Core/Util/RecentFiles.cpp +++ b/Core/Util/RecentFiles.cpp @@ -240,7 +240,7 @@ void RecentFilesManager::PerformCleanMissing() { if (!exists && TryUpdateSavedPath(&path)) { // iOS only stuff exists = File::Exists(path); - INFO_LOG(Log::UI, "Exists=%d when checking updated path: %s", exists, path.c_str()); + VERBOSE_LOG(Log::UI, "Exists=%d when checking updated path: %s", exists, path.c_str()); if (exists) { pathUpdated = true; } @@ -261,7 +261,7 @@ void RecentFilesManager::PerformCleanMissing() { cleanedRecent.push_back(pathStr); } } else { - INFO_LOG(Log::UI, "Removed '%s' from recent (couldn't access)", path.ToVisualString().c_str()); + DEBUG_LOG(Log::UI, "Removed '%s' from recent (couldn't access)", path.ToVisualString().c_str()); } } diff --git a/ios/AppDelegate.mm b/ios/AppDelegate.mm index a547240c38..6d7d9b6785 100644 --- a/ios/AppDelegate.mm +++ b/ios/AppDelegate.mm @@ -90,7 +90,9 @@ [[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]; } diff --git a/ios/IAPManager.h b/ios/IAPManager.h index af074c9b41..2daf4e2649 100644 --- a/ios/IAPManager.h +++ b/ios/IAPManager.h @@ -1,6 +1,10 @@ #import #import +#include "../ppsspp_config.h" + +#if PPSSPP_PLATFORM(IOS_APP_STORE) + @interface IAPManager : NSObject + (instancetype)sharedIAPManager; @@ -9,5 +13,8 @@ - (void)restorePurchasesWithRequestID:(int)requestID; - (BOOL)isGoldUnlocked; - (void)startObserving; +- (void)updateIcon; @end + +#endif diff --git a/ios/IAPManager.mm b/ios/IAPManager.mm index 9e7d18007d..720c3357cb 100644 --- a/ios/IAPManager.mm +++ b/ios/IAPManager.mm @@ -3,6 +3,10 @@ #include "Common/System/Request.h" #include "Common/Log.h" +#include "../ppsspp_config.h" + +#if PPSSPP_PLATFORM(IOS_APP_STORE) + // Only one operation can be in progress at once. @implementation IAPManager { SKProduct *_goldProduct; @@ -118,19 +122,54 @@ } - (void)unlockGold { + INFO_LOG(Log::UI, "Unlocking gold reward!"); + + // Write to user defaults to store the status. [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isGold"]; [[NSUserDefaults standardUserDefaults] synchronize]; - if ([[UIApplication sharedApplication] supportsAlternateIcons]) { - [[UIApplication sharedApplication] setAlternateIconName:@"GoldIcon" - completionHandler:^(NSError * _Nullable error) { - if (error) { - NSLog(@"[IAPManager] Failed to set Gold icon: %@", error.localizedDescription); - } - }]; - } + [self updateIcon]; NSLog(@"[IAPManager] Gold unlocked!"); } +- (void)updateIcon { + NSString *icon = nil; + if ([self isGoldUnlocked]) { + icon = @"AppIconGold"; + } + + NSLog(@"updateIcon called with %@", icon); + + if (![UIApplication sharedApplication]) { + NSLog(@"IAPManager: Application not initialized"); + return; + } + + NSLog(@"Current icon name: %@", [[UIApplication sharedApplication] alternateIconName]); + + if (icon) { + NSLog(@"IAPManager about to update icon to %@", icon); + } else { + NSLog(@"IAPManager about to reset the icon"); + } + NSLog(@"IAPManager: App state: %ld", (long)[UIApplication sharedApplication].applicationState); + + if ([[UIApplication sharedApplication] supportsAlternateIcons]) { + [[UIApplication sharedApplication] setAlternateIconName:icon + completionHandler:^(NSError * _Nullable error) { + if (error) { + NSLog(@"[IAPManager] Failed to set Gold icon to %@: %@", icon, error.localizedDescription); + } else { + NSLog(@"Icon update succeeded."); + } + }]; + NSLog(@"Icon update to %@ dispatched, waiting for response.", icon); + } else { + NSLog(@"Application doesn't support alternate icons."); + } +} + +#endif + @end diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist index b943029c73..1da3c1fee7 100644 --- a/ios/PPSSPP-Info.plist +++ b/ios/PPSSPP-Info.plist @@ -34,12 +34,15 @@ 1.0 CFBundleIcons - CFBundlePrimaryIcon + CFBundleAlternateIcons - CFBundleIconFiles - - assets - + AppIconGold + + CFBundleIconName + AppIconGold + UIPrerenderedIcon + + LSRequiresIPhoneOS diff --git a/ios/PPSSPPUIApplication.mm b/ios/PPSSPPUIApplication.mm index b5df31df32..aabb3695d6 100644 --- a/ios/PPSSPPUIApplication.mm +++ b/ios/PPSSPPUIApplication.mm @@ -12,6 +12,8 @@ #import #import +#import "ios/IAPManager.h" + #include "Common/System/Display.h" #include "Common/System/System.h" #include "Common/System/NativeApp.h" @@ -112,6 +114,6 @@ } } -#endif // IOS_APP_STORE +#endif // !IOS_APP_STORE @end diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 15d56062ce..109eae1c0c 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -10,6 +10,7 @@ #import "DisplayManager.h" #include "Controls.h" #import "iOSCoreAudio.h" +#import "IAPManager.h" #import #include @@ -237,6 +238,13 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { INFO_LOG(Log::G3D, "viewDidAppear"); [self hideKeyboard]; [self updateGesture]; + + // This needs to be called really late during startup, unfortunately. +#if PPSSPP_PLATFORM(IOS_APP_STORE) + [IAPManager sharedIAPManager]; // Kick off the IAPManager early. + NSLog(@"GL: viewDidAppear. updating icon"); + [[IAPManager sharedIAPManager] updateIcon]; +#endif // IOS_APP_STORE } - (void)viewDidLoad { diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index 38cf6ddf35..1415b1a2a5 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -3,6 +3,7 @@ #import "DisplayManager.h" #include "Controls.h" #import "iOSCoreAudio.h" +#import "IAPManager.h" #include "Common/Log.h" @@ -485,6 +486,12 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye [self hideKeyboard]; [self updateGesture]; + // This needs to be called really late during startup, unfortunately. +#if PPSSPP_PLATFORM(IOS_APP_STORE) + [IAPManager sharedIAPManager]; // Kick off the IAPManager early. + NSLog(@"Metal viewDidAppear. updating icon"); + [[IAPManager sharedIAPManager] updateIcon]; +#endif // IOS_APP_STORE } - (BOOL)prefersHomeIndicatorAutoHidden { diff --git a/ios/main.mm b/ios/main.mm index 6a8f069fde..9a346209e3 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -377,11 +377,17 @@ bool System_GetPropertyBool(SystemProperty prop) { #ifdef GOLD // This is deprecated. return true; -#else +#elif PPSSPP_PLATFORM(IOS_APP_STORE) return [[IAPManager sharedIAPManager] isGoldUnlocked]; +#else + return false; #endif case SYSPROP_USE_IAP: +#if PPSSPP_PLATFORM(IOS_APP_STORE) && !defined(GOLD) return true; +#else + return false; +#endif case SYSPROP_CAN_JIT: return g_jitAvailable; case SYSPROP_LIMITED_FILE_BROWSING: @@ -516,6 +522,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string } return true; } +#if PPSSPP_PLATFORM(IOS_APP_STORE) case SystemRequestType::IAP_RESTORE_PURCHASES: { [[IAPManager sharedIAPManager] restorePurchasesWithRequestID:requestId]; @@ -526,6 +533,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string [[IAPManager sharedIAPManager] buyGoldWithRequestID:requestId]; return true; } +#endif /* // Not 100% sure the threading is right case SystemRequestType::COPY_TO_CLIPBOARD: