Stripe PaymentSheet with async/await as a call anywhere UIKit extension

By Ryan Romanchuk
On
import UIKit
import class Stripe.PaymentSheet
import enum Stripe.PaymentSheetResult

extension UIViewController {
    func showStripePaymentSheet() async throws -> PaymentSheetResult {
        
        guard let customerId = await currentUser()?.stripe_customer_id else {
            throwFatal("Missing required customer account.")
        }
        

        let setupIntent = try await BillingService.createSetupIntent()
        let ephemeralKey = try await StripeUserService.fetchEphemeralKey()

        var configuration = PaymentSheet.Configuration()
        configuration.allowsDelayedPaymentMethods = true
        configuration.customer = .init(id: customerId, ephemeralKeySecret: ephemeralKey.secret)
        configuration.returnURL = C.Stripe.config.return_url
        
        
        let paymentSheet = PaymentSheet(setupIntentClientSecret: setupIntent.client_secret, configuration: configuration)
        
        let result: PaymentSheetResult = await withCheckedContinuation { continuation in
            paymentSheet.present(from: self) { paymentResult in
                continuation.resume(returning: paymentResult)
            }
        }
        
        switch result {
        case .completed:
            break
        case .canceled, .failed:
            async let _ = try? await BillingService.cancelSetupIntent(setupIntent.id)
        }
        
        return result
    }
}

Usage

class MyViewController: UIViewController {
    func updateCard() {
        Task {
            do {
                let result = try await showStripePaymentSheet()
                switch result {
                case .completed:
                    // showSuccess()
                default:
                    break
                }
            } catch {
                log.error(error)
            }
        }
    }
}
talk