diff --git a/CHANGELOG.md b/CHANGELOG.md index a96d7b8d..23e5557b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Changelog +### v2.0.1 Jun 4, 2026 + +* Upgrade IAP SDK for Android `1.6.8` and for iOS `1.6.7`. + ### v1.7.6 Jun 03, 2024 * Upgrade IAP SDK for Android `1.6.6` and for iOS `1.6.3`. diff --git a/README.md b/README.md index c1b78549..abded3f0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ The In-App Payments plugin for Square [In-App Payments SDK] is a wrapper for the native Android and iOS SDKs and supports the following native In-App Payments SDK versions: - * iOS: `1.6.5` + * iOS: `1.6.7` * Android: `1.6.8` ## Additional documentation diff --git a/SquareInAppPayments.podspec b/SquareInAppPayments.podspec index 5d05f4d1..c9f89333 100644 --- a/SquareInAppPayments.podspec +++ b/SquareInAppPayments.podspec @@ -24,7 +24,7 @@ Pod::Spec.new do |s| s.dependency 'SquareInAppPaymentsSDK', $sqipVersion s.dependency 'SquareBuyerVerificationSDK', $sqipVersion else - s.dependency 'SquareInAppPaymentsSDK', '1.6.5' - s.dependency 'SquareBuyerVerificationSDK', '1.6.5' + s.dependency 'SquareInAppPaymentsSDK', '1.6.7' + s.dependency 'SquareBuyerVerificationSDK', '1.6.7' end end diff --git a/ios/internal/SQIPBuyerInternal.m b/ios/internal/SQIPBuyerInternal.m index c3fe16e9..c666f384 100644 --- a/ios/internal/SQIPBuyerInternal.m +++ b/ios/internal/SQIPBuyerInternal.m @@ -37,49 +37,63 @@ + (void)startBuyerVerificationFlow:(nonnull NSString *)paymentSourceId [SQIPBuyerAction fromStringDictionary:buyerActionString money:moneyMap]; SQIPContact *contact = [SQIPContact fromDictionary:contactMap]; - UIViewController *rootViewController = - [UiUtilities activeRootViewController]; - SQIPVerificationParameters *params = [[SQIPVerificationParameters alloc] initWithPaymentSourceID:paymentSourceId buyerAction:buyerAction locationID:locationId contact:contact]; - if ([rootViewController isKindOfClass:[UINavigationController class]]) { - [rootViewController.navigationController popViewControllerAnimated:YES]; - } else { - [rootViewController dismissViewControllerAnimated:YES completion:nil]; - } - - [SQIPBuyerVerificationSDK.shared verifyWithParameters:params - theme:[SQIPCardEntryInternal theme] - viewController:rootViewController - success:^(SQIPBuyerVerifiedDetails *_Nonnull verifiedDetails) { - NSDictionary *verificationResult = @{ - @"nonce" : paymentSourceId, - @"token" : verifiedDetails.verificationToken - }; - onBuyerVerificationSuccess(@[ verificationResult ]); - [SQIPBuyerInternal shouldContinue]; - } - failure:^(NSError *_Nonnull error) { - NSString *debugCode = error.userInfo[SQIPErrorDebugCodeKey]; - NSString *debugMessage = error.userInfo[SQIPErrorDebugMessageKey]; - if (_mockBuyerVerification) { - NSDictionary *verificationResult = - @{@"nonce" : paymentSourceId, @"token" : @"mock-token"}; + // Capture the success/failure blocks so we can present from the dismissal + // completion handler. We need to wait for any in-progress dismissal to + // finish before handing 3DS_SDK a presenter — otherwise it tries to + // present on a VC whose view is mid-removal from the window hierarchy, + // which surfaces as "view is not in the window hierarchy" under the new + // React Native architecture (RCTFabricModalHostViewController). + void (^presentVerification)(void) = ^{ + UIViewController *presenter = [UiUtilities activeRootViewController]; + [SQIPBuyerVerificationSDK.shared verifyWithParameters:params + theme:[SQIPCardEntryInternal theme] + viewController:presenter + success:^(SQIPBuyerVerifiedDetails *_Nonnull verifiedDetails) { + NSDictionary *verificationResult = @{ + @"nonce" : paymentSourceId, + @"token" : verifiedDetails.verificationToken + }; onBuyerVerificationSuccess(@[ verificationResult ]); [SQIPBuyerInternal shouldContinue]; - } else { - [SQIPBuyerInternal invalidateShouldContinue]; - onBuyerVerificationFailure(@[ [ErrorUtilities - callbackErrorObject:RNSQIPUsageError - message:error.localizedDescription - debugCode:debugCode - debugMessage:debugMessage] ]); } - }]; + failure:^(NSError *_Nonnull error) { + NSString *debugCode = error.userInfo[SQIPErrorDebugCodeKey]; + NSString *debugMessage = error.userInfo[SQIPErrorDebugMessageKey]; + if (_mockBuyerVerification) { + NSDictionary *verificationResult = + @{@"nonce" : paymentSourceId, @"token" : @"mock-token"}; + onBuyerVerificationSuccess(@[ verificationResult ]); + [SQIPBuyerInternal shouldContinue]; + } else { + [SQIPBuyerInternal invalidateShouldContinue]; + onBuyerVerificationFailure(@[ [ErrorUtilities + callbackErrorObject:RNSQIPUsageError + message:error.localizedDescription + debugCode:debugCode + debugMessage:debugMessage] ]); + } + }]; + }; + + UIViewController *activeViewController = + [UiUtilities activeRootViewController]; + + // If a modal (e.g. card entry) is on top, dismiss it first and only + // present verification once dismissal completes — `presentingViewController` + // is the VC the active modal will hand control back to. + if (activeViewController.presentingViewController != nil) { + [activeViewController.presentingViewController + dismissViewControllerAnimated:YES + completion:presentVerification]; + } else { + presentVerification(); + } }); } diff --git a/package.json b/package.json index ac1bca4a..ae328851 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-square-in-app-payments", - "version": "2.0.0", + "version": "2.0.1", "description": "An open source React Native plugin for calling Square’s native In-App Payments SDK to take in-app payments on iOS and Android.", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts",