1

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)
          }
        }
}
jstocke2
  • 51
  • 7
  • I found this: https://www.iosapptemplates.com/blog/ios-development/stripe-firebase-swift and will be following along for the next couple of days. – jstocke2 Jul 16 '20 at 02:58

1 Answers1

0

Not a Firebase expert but I'd recommend the following:

  1. Leverage the "one time payment" docs for iOS: https://stripe.com/docs/payments/accept-a-payment#ios

These show what components you set up from the iOS SDK to collect card details in your app and confirm payments from your app.

  1. Use https://github.com/firebase/functions-samples/blob/master/stripe/functions/index.js#L85-L116 as a reference to build your Firebase functions.

This shows how your Firebase function would create a PaymentIntent and return its client_secret to your mobile app.

hmunoz
  • 2,791
  • 5
  • 11
  • Thanks for the response man. I was following the first link but I'll definately check out the second link. – jstocke2 Jul 14 '20 at 23:22
  • So I changed my index.js to that index.js and I will redeploy it. I'm not really clear on what I have to do to hit those endpoints in swift (such as secret key)? Is there a guide on that? – jstocke2 Jul 14 '20 at 23:41
  • I found this: https://firebase.google.com/docs/functions/callable it has a swift example of calling add message. Trying to figure out how to adapt this to the JS functions. – jstocke2 Jul 14 '20 at 23:51