So theres no real guide to how to set up Stripe serverless with firebase in iOS. Does anybody know of some existing resource for this? I have been referring to guides where they set it up for web and I guess the backend would be the same since its using firebase. I'm currently using this guide here: How to set up firebase as server and execute stripe payment. I've followed the directions and created in JS the create Payment method in index.js. However, I need to get the secret I think and I'm not sure how to do that as its not covered. I've got the secret saved to firebase via a CLI command but I'm not sure how to retrieve it? I've been going through the stripe iOS documentation and I have the checkout created but getting the secret key in my ios app via the backend I'm not sure how to do?
Here's my code currently when hit this only goes into the guard let paymentIntentClientSecret
Still working to get a better solution.
import UIKit
import Stripe
import FirebaseFunctions
class CheckoutViewController: UIViewController, STPAuthenticationContext {
func authenticationPresentingViewController() -> UIViewController {
return self
}
var paymentIntentClientSecret: String?
lazy var functions = Functions.functions()
lazy var cardTextField: STPPaymentCardTextField = {
let cardTextField = STPPaymentCardTextField()
return cardTextField
}()
lazy var payButton: UIButton = {
let button = UIButton(type: .custom)
button.layer.cornerRadius = 5
button.backgroundColor = .systemBlue
button.titleLabel?.font = UIFont.systemFont(ofSize: 22)
button.setTitle("Pay", for: .normal)
button.addTarget(self, action: #selector(pay), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let stackView = UIStackView(arrangedSubviews: [cardTextField, payButton])
stackView.axis = .vertical
stackView.spacing = 20
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.leftAnchor.constraint(equalToSystemSpacingAfter: view.leftAnchor, multiplier: 2),
view.rightAnchor.constraint(equalToSystemSpacingAfter: stackView.rightAnchor, multiplier: 2),
stackView.topAnchor.constraint(equalToSystemSpacingBelow: view.topAnchor, multiplier: 2),
])
startCheckout()
}
@objc
func pay() {
guard let paymentIntentClientSecret = paymentIntentClientSecret else {
return;
}
// Collect card details
let cardParams = cardTextField.cardParams
let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: nil, metadata: nil)
let paymentIntentParams = STPPaymentIntentParams(clientSecret: paymentIntentClientSecret)
paymentIntentParams.paymentMethodParams = paymentMethodParams
// Submit the payment
let paymentHandler = STPPaymentHandler.shared()
paymentHandler.confirmPayment(withParams: paymentIntentParams, authenticationContext: self) { (status, paymentIntent, error) in
switch (status) {
case .failed:
self.displayAlert(title: "Payment failed", message: error?.localizedDescription ?? "")
break
case .canceled:
self.displayAlert(title: "Payment canceled", message: error?.localizedDescription ?? "")
break
case .succeeded:
self.displayAlert(title: "Payment succeeded", message: paymentIntent?.description ?? "", restartDemo: true)
break
@unknown default:
fatalError()
break
}
}
}
func displayAlert(title: String, message: String, restartDemo: Bool = false) {
DispatchQueue.main.async {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
if restartDemo {
alert.addAction(UIAlertAction(title: "Restart demo", style: .cancel) { _ in
self.cardTextField.clear()
self.startCheckout()
})
}
else {
alert.addAction(UIAlertAction(title: "OK", style: .cancel))
}
self.present(alert, animated: true, completion: nil)
}
}
func startCheckout() {
let arguments = ["amount": 100,"currency": "usd","payment_method":"card"] as [String : Any]
functions.httpsCallable("createStripePayment").call(arguments) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey] as! String
print("Error " + message + details)
}
// ...
}
//if let text = (result?.data as? [String: Any])?["text"] as? String {
//self.resultField.text = text
//print("API Call came back with " + text)
}
}
}