From ddc5ec661125256da02301dfca75a766a45ee336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 25 May 2025 11:04:40 +0200 Subject: [PATCH] Add USE_IAP option to b-appstore.sh --- CMakeLists.txt | 18 +++++++++++++++++- b-appstore.sh | 19 +++++++++++++++++-- ios/IAPManager.mm | 28 ++++++++++++++++++++++++---- ios/main.mm | 4 ++-- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5edb6fbdfa..3f2cc51e21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,10 +134,24 @@ endif() if(GOLD) add_compile_definitions(GOLD) message("Gold Build") + if(IOS_APP_STORE) + message("WARNING: Gold build for iOS is deprecated") + endif() else() message("Non-gold Build") endif() +if(USE_IAP) + if(GOLD) + message(FATAL_ERROR "USE_IAP and GOLD can't be enabled together") + endif() + if(NOT IOS_APP_STORE) + message(FATAL_ERROR "USE_IAP can only be enabled in app store builds") + endif() + message("USE_IAP for iOS enabled") + add_compile_definitions(USE_IAP) +endif() + if(IOS_APP_STORE) add_compile_definitions(PPSSPP_PLATFORM_IOS_APP_STORE) add_compile_definitions(GLES_SILENCE_DEPRECATION) @@ -191,6 +205,8 @@ option(USE_ASAN "Use address sanitizer" OFF) option(USE_UBSAN "Use undefined behaviour sanitizer" OFF) option(USE_CCACHE "Use ccache if detected" ON) option(USE_NO_MMAP "Disable mmap usage" OFF) +option(USE_IAP "IAP enabled" OFF) +option(GOLD "Gold build" OFF) if(USE_CCACHE) include(ccache) @@ -2970,7 +2986,7 @@ if(IOS AND NOT LIBRETRO) set(DISPLAY_NAME "PPSSPP") endif() if(IOS_APP_STORE) - message(STATUS "DevTeam: ${DEVELOPMENT_TEAM_ID} Icon: ${ICON_NAME} Target: ${TargetBin}") + message(STATUS "DevTeam: ${DEVELOPMENT_TEAM_ID} Icon: ${ICON_NAME} Target: ${TargetBin} Gold: ${GOLD} IAP: ${USE_IAP}") message(STATUS "CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}") # This is for injecting the version into the plist, and also copying resources. diff --git a/b-appstore.sh b/b-appstore.sh index 0cb1854f21..439af6d7ea 100755 --- a/b-appstore.sh +++ b/b-appstore.sh @@ -14,6 +14,11 @@ if [[ -z "${GOLD}" ]]; then exit 1 fi +if [[ -z "${USE_IAP}" ]]; then + echo "USE_IAP is not set (should be YES or NO), exiting" + exit 1 +fi + FOLDER_NAME="build-ios" if [[ "$GOLD" = "YES" ]]; then @@ -23,6 +28,16 @@ else echo "Non-GOLD build." fi +if [[ "$USE_IAP" = "YES" ]]; then + if [[ "$GOLD" = "YES" ]]; then + echo "IAP and GOLD are both set to YES, which is invalid" + exit 1 + fi + echo "IAP on." +else + echo "IAP off." +fi + echo "Clearing and re-creating output directory" rm -rf $FOLDER_NAME mkdir $FOLDER_NAME @@ -31,7 +46,7 @@ pushd $FOLDER_NAME BUILD_TYPE=Release -cmake .. -DIOS_APP_STORE=ON -DGOLD=$GOLD -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/ios.cmake -DDEVELOPMENT_TEAM_ID=${DEVTEAM} -DIOS_PLATFORM=OS -GXcode +cmake .. -DIOS_APP_STORE=ON -DGOLD=$GOLD -DUSE_IAP=$USE_IAP -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/ios.cmake -DDEVELOPMENT_TEAM_ID=${DEVTEAM} -DIOS_PLATFORM=OS -GXcode # TODO: Get a MoltenVK somewhere. #cp ../MoltenVK/iOS/Frameworks/libMoltenVK.dylib PPSSPP.app/Frameworks popd @@ -45,4 +60,4 @@ echo "*** Done. Now run the following command to open in XCode, then run or arch echo " open $FOLDER_NAME/PPSSPP.xcodeproj" # To open the xcode project: -# open build-ios/PPSSPP.xcodeproj \ No newline at end of file +# open build-ios/PPSSPP.xcodeproj diff --git a/ios/IAPManager.mm b/ios/IAPManager.mm index f31af7c4f3..6cf6c2c27f 100644 --- a/ios/IAPManager.mm +++ b/ios/IAPManager.mm @@ -6,11 +6,11 @@ #include "../ppsspp_config.h" -#if PPSSPP_PLATFORM(IOS_APP_STORE) - // Only one operation can be in progress at once. @implementation IAPManager { +#ifdef USE_IAP SKProduct *_goldProduct; +#endif int _pendingRequestID; } @@ -24,21 +24,30 @@ } - (instancetype)init { +#ifdef USE_IAP if (self = [super init]) { [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } +#endif return self; } - (void)startObserving { +#ifdef USE_IAP [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; +#endif } - (BOOL)isGoldUnlocked { +#ifdef USE_IAP return [[NSUserDefaults standardUserDefaults] boolForKey:@"isGold"]; +#else + return false; +#endif } - (void)buyGoldWithRequestID:(int)requestID { +#ifdef USE_IAP if (_pendingRequestID) { ERROR_LOG(Log::IAP, "A transaction is pending. Failing the new request."); g_requestManager.PostSystemFailure(requestID); @@ -55,9 +64,13 @@ NSLog(@"[IAPManager] In-App Purchases are disabled (requestID: %d)", requestID); g_requestManager.PostSystemFailure(requestID); } +#else + g_requestManager.PostSystemFailure(requestID); +#endif } - (void)restorePurchasesWithRequestID:(int)requestID { +#ifdef USE_IAP if (_pendingRequestID) { ERROR_LOG(Log::IAP, "A transaction is pending. Failing the new request."); g_requestManager.PostSystemFailure(requestID); @@ -68,8 +81,13 @@ // NOTE: This is deprecated, but StoreKit 2 is swift only. We'll keep using it until // there's a replacement. [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; +#else + g_requestManager.PostSystemFailure(requestID); +#endif } +#ifdef USE_IAP + - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue { NSLog(@"Restore completed successfully (requestID: %d)", _pendingRequestID); g_requestManager.PostSystemSuccess(_pendingRequestID, "", 0); @@ -122,7 +140,10 @@ } } +#endif + - (void)unlockGold { +#ifdef USE_IAP INFO_LOG(Log::UI, "Unlocking gold reward!"); // Write to user defaults to store the status. @@ -134,6 +155,7 @@ }); NSLog(@"[IAPManager] Gold unlocked!"); +#endif } static bool SafeStringEqual(NSString *a, NSString *b) { @@ -185,6 +207,4 @@ static bool SafeStringEqual(NSString *a, NSString *b) { } } -#endif - @end diff --git a/ios/main.mm b/ios/main.mm index 9a346209e3..a72fe3e1ef 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -373,17 +373,17 @@ bool System_GetPropertyBool(SystemProperty prop) { // If a hardware keyboard is connected, and we add support, we could return false here. return true; case SYSPROP_APP_GOLD: - // TODO: Check the IAP status. #ifdef GOLD // This is deprecated. return true; #elif PPSSPP_PLATFORM(IOS_APP_STORE) + // Check the IAP status. return [[IAPManager sharedIAPManager] isGoldUnlocked]; #else return false; #endif case SYSPROP_USE_IAP: -#if PPSSPP_PLATFORM(IOS_APP_STORE) && !defined(GOLD) +#if PPSSPP_PLATFORM(IOS_APP_STORE) && defined(USE_IAP) return true; #else return false;