stripe / stripe-ios

Stripe iOS SDK
https://stripe.com
MIT License
2.09k stars 975 forks source link

Unable to dismiss the webview after using FPX 3D Secure authentication. #1582

Closed MartinHor closed 3 years ago

MartinHor commented 4 years ago

Summary

I'm using Fpx as the payment method, after authentication the 3D Secure authentication in the webview, my screen stuck at the webview with the "Return to merchant" button and the button is not working, i have to press the close button of the webview to dismiss the webview in order to direct myself back to the apps. I'm using swift.

Code to reproduce

extension CheckoutVC: STPPaymentContextDelegate, STPAuthenticationContext{ func authenticationPresentingViewController() -> UIViewController { return (self.navigationController?.topViewController)! } func paymentContextDidChange(_ paymentContext: STPPaymentContext) { //Updating the selected payment method if let paymentMethod = paymentContext.selectedPaymentOption{ paymentMethodBtn.setTitle(paymentMethod.label, for: .normal) }else{ paymentMethodBtn.setTitle("Select Method", for: .normal) }

    //Updating the selected shipping method
    if  paymentContext.shippingAddress != nil {
        shippingMethodBtn.setTitle("Selected", for: .normal)
        StripeCart.shippingFees = Int(0.01 * 100)
        setupPaymentInfo()
    }else{
        shippingMethodBtn.setTitle("Select", for: .normal)
    }
}

func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) {
    activityIndicator.stopAnimating()

    let alertController = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)

    let cancel = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
        self.navigationController?.popViewController(animated: true)
    }
    let retry = UIAlertAction(title: "Retry", style: .default) { (action) in
        self.paymentContext.retryLoading()
    }

    alertController.addAction(cancel)
    alertController.addAction(retry)
    present(alertController, animated: true, completion: nil)
}

//MARK: Step 1: Function for Begin a Stripe Charge
//Here is where we are going to call our Cloud Function that actually sends the information to stripe
func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPPaymentStatusBlock) {

    //For FPX
    let data : [String: Any] = [
        "total" : StripeCart.total,
        "customerId" : UserService.user.stripeId

    ]

    Functions.functions().httpsCallable("createFpxCharge").call(data) { (result, error) in
        //If error happen
        if let error = error {
            debugPrint(error.localizedDescription)
            self.simpleAlert(title: "Error", msg: "\(error.localizedDescription)")
            print("Cannot create Payment Intent")
            completion(STPPaymentStatus.error, error)
            return
        }

        guard let clientSecretKey = result?.data as? String else{
            completion(.error,nil)
            return
        }

        let paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecretKey)
        paymentIntentParams.configure(with: paymentResult)
        paymentIntentParams.returnURL = "payments-example://stripe-redirect"
        STPPaymentHandler.shared().confirmPayment(withParams: paymentIntentParams, authenticationContext: self) { status, paymentIntent, error in
            switch status {
            case .succeeded:
                // Our example backend asynchronously fulfills the customer's order via webhook
                // See https://stripe.com/docs/payments/payment-intents/ios#fulfillment

                completion(.success, nil)
                print("It success")
            case .failed:
                completion(.error, error)
                print("It fail")
            case .canceled:
                completion(.userCancellation, nil)
                print("It canceled")

            @unknown default:
                completion(.error, nil)
                print("It unknown error")

            }
        }

    }

}
//MARK: Step 2: Which is the cloud function sending the information to stripe, write in javascript with VsCode

//MARK: Step 3:Function for when the payment is complete, stripe server will send the payment status here whether successful or not
func paymentContext(_ paymentContext: STPPaymentContext, didFinishWith status: STPPaymentStatus, error: Error?) {

    let title: String
    let message: String

    activityIndicator.stopAnimating()

    switch status {
    case .error:
        title = "Error"
        message = error?.localizedDescription ?? ""
    case .success:
        title = "Payment Success"
        message = "Thank you for your purchase."
    case .userCancellation:
        return
    @unknown default:
        title = "Error"
        message = error?.localizedDescription ?? ""
    }

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
    let action = UIAlertAction(title: "Ok", style: .default) { (action) in
        self.navigationController?.popToRootViewController(animated: true)
    }

    alertController.addAction(action)
    self.present(alertController, animated: true, completion: nil)

}

iOS version

IOS version 13.4

Installation method

Cocoapods

SDK version

Stripe version 19.2.0

Other information

here is the link for the video i record on my device during the testing. https://firebasestorage.googleapis.com/v0/b/haha-71f15.appspot.com/o/RPReplay_Final1590074772.MP4?alt=media&token=3c955188-6cbf-4e5c-975c-8d7a8dda2ded

yuki-stripe commented 4 years ago

Hi @MartinUcsi,

You'll need to change "payments-example://stripe-redirect" to your app's own URL. payments-example://stripe-redirect.

Follow the "Set up a return URL" instructions here: https://stripe.com/docs/payments/3d-secure#return-url

davidme-stripe commented 3 years ago

I'm closing this out, but let us know if you're still experiencing this issue.

Pal-illuminz commented 3 years ago

Simulator Screen Shot - iPhone 6 - 2021-09-16 at 10 10 49

User not auto redirect to the app after failed or confirmation with the specific card.

brascene commented 2 years ago

@davidme-stripe @yuki-stripe how does the StripeSDK decide when to show a webview and when to show a native view? I've been experiencing both scenarios, on the same iPhone, most of the cases its'a a native view, but for some 3DS cards it opens the webview. Is it related to the card type, or to something else?