在 Swift 中将账单地址链接到 iOS 上 Stripe 中的 PaymentSheet

问题描述 投票:0回答:1

下面是我的代码,主要是根据快速入门指南 (https://docs.stripe.com/ payments/quickstart) 以及 Stripe 文档的地址元素部分 (https://docs.stripe. com/elements/address-element/collect-addresses)。

import UIKit
import StripePaymentSheet

class CheckoutViewController: UIViewController {

    private static let backendURL = URL(string: "https://sundealit.com/stripetest")!

    private var paymentIntentClientSecret: String?
    private var addressViewController: AddressViewController?
    private var addressDetails: AddressViewController.AddressDetails?

    private lazy var payButton: UIButton = {
        let button = UIButton(type: .custom)
        button.setTitle("Pay now", for: .normal)
        button.backgroundColor = .systemIndigo
        button.layer.cornerRadius = 5
        button.contentEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
        button.addTarget(self, action: #selector(pay), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.isEnabled = false // Initially disabled
        return button
    }()
    
    private lazy var addressButton: UIButton = {
        let button = UIButton(type: .custom)
        button.setTitle("Add Address", for: .normal)
        button.backgroundColor = .systemIndigo
        button.layer.cornerRadius = 5
        button.contentEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
        button.addTarget(self, action: #selector(address), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.isEnabled = true // Enable this button initially so user can add address
        return button
    }()
    
    private var addressConfiguration: AddressViewController.Configuration {
        return AddressViewController.Configuration(
          additionalFields: .init(phone: .required),
          allowedCountries: ["US", "CA", "GB", "HK"],
          title: "Shipping Address"
        )
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        view.addSubview(payButton)
        view.addSubview(addressButton)

        NSLayoutConstraint.activate([
            payButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
            payButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
            payButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16)
        ])
        
        NSLayoutConstraint.activate([
            addressButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
            addressButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
            addressButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16)
        ])

        self.fetchPaymentIntent()
    }

    func fetchPaymentIntent() {
        let url = Self.backendURL.appendingPathComponent("/create-payment-intent")

        let shoppingCartContent: [String: Any] = [
            "items": [
                ["id": "xl-shirt"]
            ]
        ]

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try? JSONSerialization.data(withJSONObject: shoppingCartContent)

        let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in
            guard
                let response = response as? HTTPURLResponse,
                response.statusCode == 200,
                let data = data,
                let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any],
                let clientSecret = json["clientSecret"] as? String,
                let publishableKey = json["publishableKey"] as? String
            else {
                let message = error?.localizedDescription ?? "Failed to decode response from server."
                self?.displayAlert(title: "Error loading page", message: message)
                return
            }

            print("Created PaymentIntent")
            print(clientSecret)
            print(publishableKey)
            self?.paymentIntentClientSecret = clientSecret
            StripeAPI.defaultPublishableKey = publishableKey
            DispatchQueue.main.async {
                self?.payButton.isEnabled = true
            }
        })

        task.resume()
    }

    func displayAlert(title: String, message: String? = nil) {
        DispatchQueue.main.async {
            let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(alertController, animated: true)
        }
    }

    @objc
    func pay() {
        guard let paymentIntentClientSecret = self.paymentIntentClientSecret else {
            return
        }

        var configuration = PaymentSheet.Configuration()
        configuration.merchantDisplayName = "Example, Inc."

        let paymentSheet = PaymentSheet(
            paymentIntentClientSecret: paymentIntentClientSecret,
            configuration: configuration)

        paymentSheet.present(from: self) { [weak self] (paymentResult) in
            switch paymentResult {
            case .completed:
                self?.displayAlert(title: "Payment complete!")
            case .canceled:
                print("Payment canceled!")
            case .failed(let error):
                self?.displayAlert(title: "Payment failed", message: error.localizedDescription)
            }
        }
    }
    
    @objc
    func address() {
        self.addressViewController = AddressViewController(configuration: addressConfiguration, delegate: self)
        let navigationController = UINavigationController(rootViewController: addressViewController!)

        present(navigationController, animated: true)
    }
}

extension CheckoutViewController: AddressViewControllerDelegate {
    func addressViewControllerDidFinish(_ addressViewController: AddressViewController, with address: AddressViewController.AddressDetails?) {
        addressViewController.dismiss(animated: true)
        self.addressDetails = address
    }
}

我的问题是,现在我可以从用户那里收集地址,“收集的地址”似乎存储在任何地方,并且在用户付款时不会被调用。如果对于每次付款我都无法指明我要将产品运送到哪里,那么这样的“收集地址”对我来说就没用。那么我如何修改代码以某种方式将两者链接在一起并能够在 Stripe 后端引用它? Stripe 文档似乎没有提供任何参考代码。

请帮忙...谢谢!

ios swift stripe-payments payment-gateway
1个回答
0
投票

收集地址后,您可以将其作为 Stripe Doc 在此处提到预先填写到 PaymentSheet 配置的 ShippingDetails 中。

var configuration = PaymentSheet.Configuration()
// ...
configuration.shippingDetails = { [weak self] in
    return self?.addressDetails
}

请注意,您还希望将配置移至

pay()
函数之外,并通过地址回调填充它,然后仅在
paymentSheet.present()
函数内调用
pay()

© www.soinside.com 2019 - 2024. All rights reserved.