From b93b5ebf0d3ef5142e0d92d2a2d8b45a1ca21c0e Mon Sep 17 00:00:00 2001 From: Mark Villacampa Date: Sat, 24 Feb 2024 15:16:03 +0100 Subject: [PATCH] Updated to support PHC 10.0 --- RNPurchases.podspec | 2 +- .../purchases/react/RNPurchasesModule.java | 2 +- apitesters/purchases.ts | 21 +++++++---- examples/MagicWeather/ios/Podfile | 2 +- examples/purchaseTesterTypescript/ios/Podfile | 2 +- .../PurchaseTester.xcodeproj/project.pbxproj | 8 ++--- ios/RNPurchases.m | 19 ++++++++-- react-native-purchases-ui/RNPaywalls.podspec | 2 +- src/purchases.ts | 36 ++++++++++++++++--- 9 files changed, 72 insertions(+), 22 deletions(-) diff --git a/RNPurchases.podspec b/RNPurchases.podspec index 52089237..4bd6af2c 100644 --- a/RNPurchases.podspec +++ b/RNPurchases.podspec @@ -10,7 +10,7 @@ Pod::Spec.new do |spec| spec.authors = package['author'] spec.homepage = "https://github.com/RevenueCat/react-native-purchases" spec.license = package['license'] - spec.platform = :ios, "11.0" + spec.platform = :ios, "13.0" spec.source = { :git => "https://github.com/RevenueCat/react-native-purchases.git" } spec.source_files = "ios/**/*.{h,m,swift}" diff --git a/android/src/main/java/com/revenuecat/purchases/react/RNPurchasesModule.java b/android/src/main/java/com/revenuecat/purchases/react/RNPurchasesModule.java index a3473b5c..3f980fda 100644 --- a/android/src/main/java/com/revenuecat/purchases/react/RNPurchasesModule.java +++ b/android/src/main/java/com/revenuecat/purchases/react/RNPurchasesModule.java @@ -82,7 +82,7 @@ public void removeListeners(Integer count) { @ReactMethod public void setupPurchases(String apiKey, @Nullable String appUserID, boolean observerMode, @Nullable String userDefaultsSuiteName, - @Nullable Boolean usesStoreKit2IfAvailable, boolean useAmazon, + @Nullable String storeKitVersion, boolean useAmazon, boolean shouldShowInAppMessagesAutomatically, @Nullable String entitlementVerificationMode) { PlatformInfo platformInfo = new PlatformInfo(PLATFORM_NAME, PLUGIN_VERSION); diff --git a/apitesters/purchases.ts b/apitesters/purchases.ts index 07db2538..963178a8 100644 --- a/apitesters/purchases.ts +++ b/apitesters/purchases.ts @@ -1,4 +1,4 @@ -import {ENTITLEMENT_VERIFICATION_MODE, IN_APP_MESSAGE_TYPE} from '@revenuecat/purchases-typescript-internal'; +import {ENTITLEMENT_VERIFICATION_MODE, IN_APP_MESSAGE_TYPE, STOREKIT_VERSION} from '@revenuecat/purchases-typescript-internal'; import { CustomerInfo, PurchasesEntitlementInfo, @@ -124,13 +124,14 @@ async function checkPurchasing(purchases: Purchases, await Purchases.showInAppMessages(); await Purchases.showInAppMessages(messageTypes); + await Purchases.handleObserverModeTransaction("product_id"); } async function checkConfigure() { const apiKey: string = ""; const appUserID: string | null = ""; const observerMode: boolean = false; - const usesStoreKit2IfAvailable: boolean = true; + const storeKitVersion: STOREKIT_VERSION = Purchases.STOREKIT_VERSION.DEFAULT; const useAmazon: boolean = true; const entitlementVerificationMode: ENTITLEMENT_VERIFICATION_MODE = Purchases.ENTITLEMENT_VERIFICATION_MODE.INFORMATIONAL; const userDefaultsSuiteName: string = ""; @@ -152,14 +153,14 @@ async function checkConfigure() { appUserID, observerMode, userDefaultsSuiteName, - usesStoreKit2IfAvailable + storeKitVersion }); Purchases.configure({ apiKey, appUserID, observerMode, userDefaultsSuiteName, - usesStoreKit2IfAvailable, + storeKitVersion, entitlementVerificationMode }); Purchases.configure({ @@ -167,7 +168,7 @@ async function checkConfigure() { appUserID, observerMode, userDefaultsSuiteName, - usesStoreKit2IfAvailable, + storeKitVersion, entitlementVerificationMode, useAmazon }); @@ -176,7 +177,7 @@ async function checkConfigure() { appUserID, observerMode, userDefaultsSuiteName, - usesStoreKit2IfAvailable, + storeKitVersion, useAmazon, shouldShowInAppMessagesAutomatically }); @@ -213,6 +214,14 @@ async function checkEntitlementVerificationModeEnum(mode: ENTITLEMENT_VERIFICATI } } +function checkStoreKitVersion(status: STOREKIT_VERSION) { + switch (status) { + case STOREKIT_VERSION.DEFAULT: + case STOREKIT_VERSION.STOREKIT_1: + case STOREKIT_VERSION.STOREKIT_2: + } +} + function checkListeners() { const customerInfoUpdateListener: CustomerInfoUpdateListener = customerInfo => { }; diff --git a/examples/MagicWeather/ios/Podfile b/examples/MagicWeather/ios/Podfile index e4d97a4e..cba9edab 100644 --- a/examples/MagicWeather/ios/Podfile +++ b/examples/MagicWeather/ios/Podfile @@ -1,7 +1,7 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, '11.0' +platform :ios, '13.0' target 'MagicWeatherReactNative' do config = use_native_modules! diff --git a/examples/purchaseTesterTypescript/ios/Podfile b/examples/purchaseTesterTypescript/ios/Podfile index 145b5f32..436377a2 100644 --- a/examples/purchaseTesterTypescript/ios/Podfile +++ b/examples/purchaseTesterTypescript/ios/Podfile @@ -1,7 +1,7 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, min_ios_version_supported +platform :ios, "13.0" prepare_react_native_project! # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. diff --git a/examples/purchaseTesterTypescript/ios/PurchaseTester.xcodeproj/project.pbxproj b/examples/purchaseTesterTypescript/ios/PurchaseTester.xcodeproj/project.pbxproj index 7ac4519f..c75c067f 100644 --- a/examples/purchaseTesterTypescript/ios/PurchaseTester.xcodeproj/project.pbxproj +++ b/examples/purchaseTesterTypescript/ios/PurchaseTester.xcodeproj/project.pbxproj @@ -470,7 +470,7 @@ "$(inherited)", ); INFOPLIST_FILE = PurchaseTesterTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -495,7 +495,7 @@ COPY_PHASE_STRIP = NO; DEVELOPMENT_TEAM = 8SXR2327BM; INFOPLIST_FILE = PurchaseTesterTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -616,7 +616,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -690,7 +690,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", diff --git a/ios/RNPurchases.m b/ios/RNPurchases.m index 8d2fa791..4eebfdaf 100644 --- a/ios/RNPurchases.m +++ b/ios/RNPurchases.m @@ -41,7 +41,7 @@ - (dispatch_queue_t)methodQueue { appUserID:(nullable NSString *)appUserID observerMode:(BOOL)observerMode userDefaultsSuiteName:(nullable NSString *)userDefaultsSuiteName - usesStoreKit2IfAvailable:(BOOL)usesStoreKit2IfAvailable + storeKitVersion:(nullable NSString *)storeKitVersion useAmazon:(BOOL)useAmazon shouldShowInAppMessagesAutomatically:(BOOL)shouldShowInAppMessagesAutomatically entitlementVerificationMode:(nullable NSString *)entitlementVerificationMode) { @@ -51,8 +51,8 @@ - (dispatch_queue_t)methodQueue { userDefaultsSuiteName:userDefaultsSuiteName platformFlavor:self.platformFlavor platformFlavorVersion:self.platformFlavorVersion - usesStoreKit2IfAvailable:usesStoreKit2IfAvailable - dangerousSettings:nil + storeKitVersion:storeKitVersion + dangerousSettings:nil shouldShowInAppMessagesAutomatically:shouldShowInAppMessagesAutomatically verificationMode:entitlementVerificationMode]; purchases.delegate = self; @@ -232,6 +232,19 @@ static void logUnavailablePresentCodeRedemptionSheet() { NSLog(@"[Purchases] Warning: tried to present codeRedemptionSheet, but it's only available on iOS 14.0 or greater."); } +RCT_EXPORT_METHOD(handleObserverModeTransactionForProductID:(nonnull NSString *)productID + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { + if (@available(iOS 15.0, *)) { + [RCCommonFunctionality handleObserverModeTransactionForProductID:@"" + completion: [self getResponseCompletionBlockWithResolve:resolve + reject:reject]]; + } else { + NSLog(@"[Purchases] Warning: tried to handle Observer Mode transaction, but it's only available on iOS 15.0 or greater."); + resolve(nil); + } +} + #pragma mark - Subscriber Attributes RCT_EXPORT_METHOD(setProxyURLString:(nullable NSString *)proxyURLString) { diff --git a/react-native-purchases-ui/RNPaywalls.podspec b/react-native-purchases-ui/RNPaywalls.podspec index 6efbe343..d994c930 100644 --- a/react-native-purchases-ui/RNPaywalls.podspec +++ b/react-native-purchases-ui/RNPaywalls.podspec @@ -10,7 +10,7 @@ Pod::Spec.new do |spec| spec.authors = package['author'] spec.homepage = "https://github.com/RevenueCat/react-native-purchases" spec.license = package['license'] - spec.platform = :ios, "11.0" + spec.platform = :ios, "13.0" spec.source = { :git => "https://github.com/RevenueCat/react-native-purchases.git" } spec.source_files = "ios/**/*.{h,m,swift}" diff --git a/src/purchases.ts b/src/purchases.ts index 4e0e4a3c..b9ac11e8 100644 --- a/src/purchases.ts +++ b/src/purchases.ts @@ -31,7 +31,9 @@ import { LogInResult, IN_APP_MESSAGE_TYPE, ENTITLEMENT_VERIFICATION_MODE, - VERIFICATION_RESULT + VERIFICATION_RESULT, + STOREKIT_VERSION, + PurchasesStoreTransaction } from '@revenuecat/purchases-typescript-internal'; // This export is kept to keep backwards compatibility to any possible users using this file directly @@ -169,6 +171,13 @@ export default class Purchases { */ public static VERIFICATION_RESULT = VERIFICATION_RESULT; + /** + * Enum of StoreKit version. + * @readonly + * @enum {string} + */ + public static STOREKIT_VERSION = STOREKIT_VERSION; + /** * @internal */ @@ -184,7 +193,7 @@ export default class Purchases { * @param {String} apiKey RevenueCat API Key. Needs to be a String * @param {String?} appUserID An optional unique id for identifying the user. Needs to be a string. * @param {boolean} [observerMode=false] An optional boolean. Set this to TRUE if you have your own IAP implementation and want to use only RevenueCat's backend. Default is FALSE. - * @param {boolean} [usesStoreKit2IfAvailable=false] DEPRECATED. An optional boolean. iOS-only. Defaults to FALSE. Setting this to TRUE will enable StoreKit2 on compatible devices. + * @param {STOREKIT_VERSION} [storeKitVersion=STOREKIT_2] iOS-only. Defaults to STOREKIT_2. StoreKit 2 is only available on iOS 15+. StoreKit 1 will be used for previous iOS versions regardless of this setting. * We recommend not using this parameter, letting RevenueCat decide for you which StoreKit implementation to use. * @param {ENTITLEMENT_VERIFICATION_MODE} [entitlementVerificationMode=ENTITLEMENT_VERIFICATION_MODE.DISABLED] Sets the entitlement verifciation mode to use. For more details, check https://rev.cat/trusted-entitlements * @param {boolean} [useAmazon=false] An optional boolean. Android-only. Set this to TRUE to enable Amazon on compatible devices. @@ -197,7 +206,7 @@ export default class Purchases { appUserID = null, observerMode = false, userDefaultsSuiteName, - usesStoreKit2IfAvailable = false, + storeKitVersion = STOREKIT_VERSION.DEFAULT, useAmazon = false, shouldShowInAppMessagesAutomatically = true, entitlementVerificationMode = ENTITLEMENT_VERIFICATION_MODE.DISABLED @@ -215,7 +224,7 @@ export default class Purchases { appUserID, observerMode, userDefaultsSuiteName, - usesStoreKit2IfAvailable, + storeKitVersion, useAmazon, shouldShowInAppMessagesAutomatically, entitlementVerificationMode @@ -666,6 +675,25 @@ export default class Purchases { RNPurchases.syncObserverModeAmazonPurchase(productID, receiptID, amazonUserID, isoCurrencyCode, price); } + /** + * Use this method only if you already have your own IAP implementation using StoreKit 2 and want to use + * RevenueCat's backend. If you are using StoreKit 1 for your implementation, you do not need this method. + * + * You only need to use this method with *new* purchases. Subscription updates are observed automatically. + * + * Important: This should only be used if you have enabled observer mode during SDK configuration. + * + * @warning You need to finish the transaction yourself after calling this method. + * + * @param {string} productID Product ID that was just purchased + * @returns {Promise} If there was a transacton found and handled for the provided product ID. + */ + public static async handleObserverModeTransaction(productID: string): Promise { + await Purchases.throwIfAndroidPlatform(); + await Purchases.throwIfNotConfigured(); + return RNPurchases.handleObserverModeTransactionForProductID(productID); + } + /** * @deprecated, use enableAdServicesAttributionTokenCollection instead. * Enable automatic collection of Apple Search Ad attribution. Disabled by default