Stripe - 单一方法预构建 UI,STPAPIClient.shared().publishableKey iOS Swift UiKit

Posted

技术标签:

【中文标题】Stripe - 单一方法预构建 UI,STPAPIClient.shared().publishableKey iOS Swift UiKit【英文标题】:Stripe - single method prebuit UI, STPAPIClient.shared().publishableKey iOS Swift UiKit 【发布时间】:2021-10-31 20:24:14 【问题描述】:

我关注了这个文档:https://stripe.com/docs/payments/accept-a-payment?platform=ios&ui=payment-sheet

我从我的后端获取这些。

"clientSecret" : "pi_3JUrPkLW44AR......7WElFl", "stripecustomerid" : "cus_K8......pLu4", “paymentids”:“pi_3JVA .....R9VmA” "EphemeralKey" : "ephkey_1JV......kEtnlw"

//PaymentSheet Configuration

 let clientSecret = response["clientSecret"].stringValue            
 let ephemeralSecret = response["EphemeralKey"].stringValue
 let cusId = response["stripecustomerid"].stringValue

 // MARK: Set your Stripe publishable key - this allows the SDK to make requests to Stripe for your account

    STPAPIClient.shared.publishableKey = self.publishableKey

 // MARK: Create a PaymentSheet instance
    var configuration = PaymentSheet.Configuration()
    configuration.merchantDisplayName = "Z*****"
    configuration.customer = .init( id: cusId, ephemeralKeySecret: ephemeralSecret)
    configuration.returnURL = "payments-example://stripe-redirect"
    self.paymentSheet = PaymentSheet(
                    paymentIntentClientSecret: clientSecret,
                    configuration: configuration)

在此之后(付款开始)我从条带获取日志:

日志分析:[“product_usage”:[“PaymentSheet”],“app_name”:“Zucraz”,“additional_info”:[],“bindings_version”:“21.8.1”,“apple_pay_enabled”:0,“ocr_type “:“无”,“os_version”:“14.4”,“analytics_ua”:“analytics.stripeios-1.0”,“ui_usage_level”:“部分”,“publishable_key”:“pk_test_51J9Te0LW............tRQbRP2 ", "device_type": "iPhone12,1", "event": "mc_complete_init_customer", "app_version": "3.4"]

调用此方法时 - 显示 PaymentSheet

func openPaymentSheet()
        // MARK: Start the checkout process
        paymentSheet?.present(from: self)  paymentResult in
            // MARK: Handle the payment result
            switch paymentResult 
            case .completed:
                self.displayAlert("Your order is confirmed!")
            case .canceled:
                print("Canceled!")
            case .failed(let error):
                print(error)
                self.displayAlert("Payment failed: \n\(error.localizedDescription)")
            
        
    

收到此错误

Error Domain=com.stripe.lib Code=50 "There was an unexpected error -- try again in a few seconds" UserInfo=NSLocalizedDescription=There was an unexpected error -- try again in a few seconds, com.stripe.lib:ErrorMessageKey=No valid API key provided. Set `STPAPIClient.shared().publishableKey` to your publishable key, which you can find here: https://stripe.com/docs/keys, com.stripe.lib:StripeErrorTypeKey=invalid_request_error, com.stripe.lib:StripeErrorCodeKey=

文档中没有定义设置 STPAPIClient.shared().publishableKey。 仍然,我尝试在我的视图控制器中设置 STPAPIClient.shared.publishableKey,但仍然收到错误。

提前致谢

完整的类代码:

导入 UIKit 导入 SwiftyJSON 导入 FirebaseAnalytics 导入条纹 导入 PassKit

类 ReviewOrderViewC: UIViewController,UITableViewDelegate,UITableViewDataSource

@IBOutlet weak var viewForEmptyCart: UIView!
@IBOutlet weak var lblCity: UILabel!
@IBOutlet weak var lblNsmr: UILabel!
@IBOutlet weak var lblAdress: UILabel!
@IBOutlet weak var lblMobile: UILabel!
var responseData : JSON = []
@IBOutlet weak var tblReview: UITableView!

@IBOutlet weak var btnCod: UIButton!

@IBOutlet weak var btnOnlinePayment: UIButton!
@IBOutlet weak var lblApplyCoupon: UILabel!
@IBOutlet weak var viewForApplyCoupon: UIView!
@IBOutlet weak var txtCouponCode: UITextField!

@IBOutlet weak var lblCartTotalAmount: UILabel!
@IBOutlet weak var lblTotalAmount: UILabel!
@IBOutlet weak var viewBlankForCoupn: UIView!
var paymentType = "cod"
var couponCode = ""
@IBOutlet weak var lblEmptyCartText: UILabel!
@IBOutlet weak var lblAddInCartText: UILabel!
@IBOutlet weak var btnContinueSaida: CustomButton!

@IBOutlet weak var lblReviewOrder: UILabel!

@IBOutlet weak var lblMobileText: UILabel!
@IBOutlet weak var btnEditChange: UIButton!
@IBOutlet weak var lblOnlineText: UILabel!

@IBOutlet weak var lblCODText: UILabel!
@IBOutlet weak var lblPaymentMethodText: UILabel!

@IBOutlet weak var lblPriceDetailsText: UILabel!
@IBOutlet weak var lblCartTotalText: UILabel!

@IBOutlet weak var lblTotalAmountText: UILabel!

@IBOutlet weak var btnProcedd: CustomButton!
@IBOutlet weak var lblCouponText: UILabel!
@IBOutlet weak var btnApplyCoupon: UIButton!
@IBOutlet weak var lblDelivery: UILabel!
@IBOutlet weak var lblDeliveryText: UILabel!
@IBOutlet weak var lblDelTime: UILabel!
@IBOutlet weak var lblDiscountText: UILabel!
@IBOutlet weak var lblDiscount: UILabel!
@IBOutlet weak var lblFreeDel: UILabel!
@IBOutlet weak var lblCreditText: UILabel!
@IBOutlet weak var lblCreditPointText: UILabel!


@IBOutlet weak var btnRemoveCoupon: UIButton!

var addressData : JSON = []
var couponAmt = "0"

//For Stripe
var customerContext : STPCustomerContext?
var paymentContext : STPPaymentContext?
var isSetShipping = false
var paymentSheet: PaymentSheet?
var clientSecret = ""
var ephemeralKeySecret = ""
var paymentSheetFlowController: PaymentSheet.FlowController!
@IBOutlet weak var buyButton: UIButton!
@IBOutlet weak var paymentMethodButton: UIButton!
@IBOutlet weak var paymentMethodImage: UIImageView!
let publishableKey = "pk_test_51J***************bRP2"



override func viewDidLoad() 
    super.viewDidLoad()
    

    self.orderReview()
    viewForApplyCoupon.isHidden = true
    viewBlankForCoupn.isHidden = true
    
    
    //Add Tap Gesture on Blank view to hide apply Coupon
    let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
    viewBlankForCoupn.addGestureRecognizer(tap)
    viewForApplyCoupon.layer.cornerRadius = 8
    viewForApplyCoupon.clipsToBounds = true
    btnCod.setImage(#imageLiteral(resourceName: "radio"), for: .normal)
 //   viewForEmptyCart.isHidden = true
    
    lblReviewOrder.text = "reviewOrder".localizableSting()
    lblMobileText.text = "mobile".localizableSting() + " :"
    btnEditChange.setTitle("edit".localizableSting(), for: .normal)
    lblPaymentMethodText.text = "paymentMethod".localizableSting()
    lblCODText.text = "cod".localizableSting()
    lblOnlineText.text = "online".localizableSting()
    lblApplyCoupon.text = "applyCoupon".localizableSting()
    lblPriceDetailsText.text = "priceDetails".localizableSting()
    lblCartTotalText.text = "cartTotal".localizableSting()
    lblTotalAmountText.text = "total".localizableSting()
    
    btnProcedd.setTitle("proceedReview".localizableSting(), for: .normal)
    
    lblEmptyCartText.text = "blankCartText".localizableSting()
    lblAddInCartText.text = "addInCartText".localizableSting()
    btnContinueSaida.setTitle("continueSaida".localizableSting(), for: .normal)
    
    lblCouponText.text = "coupon".localizableSting()
    txtCouponCode.placeholder = "txtCoupon".localizableSting()
    btnApplyCoupon.setTitle("apply".localizableSting(), for: .normal)
    
    btnOnlinePayment.isEnabled = true
    self.lblDeliveryText.text = "deliveryCharges".localizableSting()
    
    
    self.lblNsmr.text = self.addressData["fname"].stringValue + " " + self.addressData["lname"].stringValue
    self.lblAdress.text = "\(self.addressData["address"].stringValue),  \(self.addressData["state"].stringValue), \(self.addressData["city"].stringValue)"
    self.lblMobile.text = self.addressData["mobileno"].stringValue
    
    if NetworkManeger.getWalletStatus() == "0" 
        lblCreditText.isHidden = true
        lblCreditPointText.isHidden = true
    else
        lblCreditText.isHidden = false
        lblCreditPointText.isHidden = false
    
    self.intiateStripePayment()



@objc func handleTap(_ sender: UITapGestureRecognizer? = nil) 
    // handling code
    viewForApplyCoupon.isHidden = true
    viewBlankForCoupn.isHidden = true


@IBAction func btnCODAction(_ sender: Any) 
    paymentType = "cod"
    btnCod.setImage(#imageLiteral(resourceName: "radio"), for: .normal)
    btnOnlinePayment.setImage(#imageLiteral(resourceName: "contact_us_icon-1"), for: .normal)


@IBAction func btnOnlineAction(_ sender: Any) 
    if self.responseData["totalcost"].floatValue > 0 
        paymentType = "online"
        btnOnlinePayment.setImage(#imageLiteral(resourceName: "radio"), for: .normal)
        btnCod.setImage(#imageLiteral(resourceName: "contact_us_icon-1"), for: .normal)
    
    


@IBAction func btnApplyCouponAction(_ sender: Any) 
    //Show blank view and coupon code view
    viewForApplyCoupon.isHidden = false
    viewBlankForCoupn.isHidden = false


@IBAction func btnApplyCouponCode(_ sender: Any) 
    //Call after response from API
    couponCode = txtCouponCode.text ?? ""
    txtCouponCode.resignFirstResponder()
    //orderReview()
    addCoupon()

    viewForApplyCoupon.isHidden = true
    viewBlankForCoupn.isHidden = true


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return self.responseData["productdetails"].count


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
   let cell = tableView.dequeueReusableCell(withIdentifier: "ReviewOrderTableViewCell", for: indexPath) as! ReviewOrderTableViewCell
    
    let imgURLString = self.responseData["productdetails"][indexPath.row]["imageurl"].stringValue
    let newImageUrlStr = imgURLString.replacingOccurrences(of: " ", with: "%20")
    let imageUrl =  URL(string:newImageUrlStr)
    cell.imgCartProduct.af_setImage(withURL:imageUrl!)
    
    cell.lblCartProductName.text = self.responseData["productdetails"][indexPath.row]["productname"].stringValue
    cell.lblPrice.text = self.responseData["productdetails"][indexPath.row]["sellingprice"].stringValue + " " + "JD".localizableSting()
    cell.lblQuantity.text = self.responseData["productdetails"][indexPath.row]["qty"].stringValue
    
    cell.lblBySaidaText.text = "bySaida".localizableSting()
    cell.lblSizeText.text = "size".localizableSting() + " : "
    cell.lblSize.text = self.responseData["productdetails"][indexPath.row]["size"].stringValue
    cell.lblQtyText.text = "qty".localizableSting() + " : "
    
    cell.btnRemove.addTarget(self, action: #selector(remove(sender:)), for: .touchUpInside)
    cell.btnRemove.tag = indexPath.row
    
    return cell



@objc func remove(sender: UIButton) 
    
    
    let altMessage = UIAlertController(title: "ZUCRAZ", message: "Remove this item from cart.", preferredStyle: UIAlertController.Style.alert)
    altMessage.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: 
        _ in
        if NetworkManeger.isConnectedToNetwork()
            let cartId = NetworkManeger.getCartId()
            let productId = self.responseData["productdetails"][sender.tag]["pid"].stringValue
            
            NetworkManeger.postRequest(remainingUrl: "deleteCartProduct.php", parameters: ["cartid": cartId, "pid": productId])  (response) in
              if response["status"].intValue == 200 
                  self.orderReview()
              else
                  NetworkManeger.showAlertWithMsg(vc: self, msg: response["msg"].stringValue)
              
                    
            
        else
            
            let altMessage = UIAlertController(title: "ZUCRAZ", message: "Please check internet connection!", preferredStyle: UIAlertController.Style.alert)
            altMessage.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
            self.present(altMessage, animated: true, completion: nil)
        
    ))
    altMessage.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.default, handler: nil))
    self.present(altMessage, animated: true, completion: nil)
    




@IBAction func btnBack(_ sender: UIButton) 
    self.navigationController?.popViewController(animated: true)


@IBAction func btnProceed(_ sender: UIButton) 

    self.openPaymentSheet()
   
    


        

//MARKS: API HIT

func intiateStripePayment()

    NetworkManeger.postRequest(remainingUrl: "stripepaymentinitiate.php", parameters: ["cartid": NetworkManeger.getCartId(), "user_id" : NetworkManeger.getUserId()])  (response) in
        
        if response["status"].intValue == 200 
            //Get ephmeral Key and clientSecret
            self.clientSecret = response["clientSecret"].stringValue
           // self.clientSecret = response["paymentintent"][0]["secret"].stringValue
            self.ephemeralKeySecret = response["EphemeralKey"][0]["id"].stringValue
            
            let cusId = NetworkManeger.getStripCustomerId()
            // MARK: Set your Stripe publishable key - this allows the SDK to make requests to Stripe for your account
            STPAPIClient.shared.publishableKey = self.publishableKey

            // MARK: Create a PaymentSheet instance
            var configuration = PaymentSheet.Configuration()
            configuration.merchantDisplayName = "Zucraz"
            configuration.customer = .init(
                id: cusId, ephemeralKeySecret:  self.ephemeralKeySecret)
            configuration.returnURL = "payments-example://stripe-redirect"
            self.paymentSheet = PaymentSheet(
                paymentIntentClientSecret: self.clientSecret,
                configuration: configuration)

            DispatchQueue.main.async 
                self.buyButton.isEnabled = true
            
        
    




func openPaymentSheet()
    // MARK: Start the checkout process
    self.paymentSheet?.present(from: self)  paymentResult in
        // MARK: Handle the payment result
        switch paymentResult 
        case .completed:
            self.displayAlert("Your order is confirmed!")
        case .canceled:
            print("Canceled!")
        case .failed(let error):
            print(error)
            self.displayAlert("Payment failed: \n\(error.localizedDescription)")
        
    


func displayAlert(_ message: String) 
    let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
    let OKAction = UIAlertAction(title: "OK", style: .default)  (action) in
        alertController.dismiss(animated: true) 
            self.navigationController?.popViewController(animated: true)
        
    
    alertController.addAction(OKAction)
    present(alertController, animated: true, completion: nil)


   func orderReview()
    self.responseData = []
    NetworkManeger.postRequest(remainingUrl: "orderReviewAPI.php", parameters: ["cartid": NetworkManeger.getCartId(), "user_id" : NetworkManeger.getUserId() , "coupondiscount" : couponCode, "applang" : NetworkManeger.getAppLang(), "iswalletused" : NetworkManeger.getWalletStatus(), "address_id" : self.addressData["address_id"].stringValue])  
   



func addCoupon()
       NetworkManeger.postRequest(remainingUrl: "cartcouponapply.php", parameters: ["cartid": NetworkManeger.getCartId(), "user_id" : NetworkManeger.getUserId() , "promocode" : couponCode, "cartvalue" : self.responseData["subtotal"].stringValue])  

【问题讨论】:

如果您不设置临时密钥,也会出现该错误,不幸的是,该错误有点令人困惑。你能分享你的完整代码吗?包括实际解析服务器响应并使用客户详细信息创建PaymentSheet.Configuration() 的部分? 嗨@karllekko 添加了支付配置代码。 你能记录下例如的值吗? ephemeralSecret 并确保它不是零?您还应该在使用时记录self.publishableKey,只需进行一些调试以检查这些变量是否意外地为零。 也可能不相关,但您正在配置 self.paymentSheet 但稍后您将展示 paymentSheet ,因此由于它不引用 self 您可能有两个 PaymentSheet 变量实例并且只配置了其中一个?不看完整的代码很难说。 response["EphemeralKey"][0]["id"].stringValue 在我看来不合适。您不需要密钥的 ID,您需要从 API(stripe.com/docs/payments/…) 返回的对象的 secret 值。您拥有的值应该类似于 ek_test_xxx ,而不是 ephkey_xxx 【参考方案1】:

不要对错误感到困惑:“将STPAPIClient.shared().publishableKey 设置为您的可发布密钥”。

与此无关。

如果遇到此类错误,请检查您的密钥。

EphemeralKey 必须类似于:ek_test_xxx(秘密)。

【讨论】:

以上是关于Stripe - 单一方法预构建 UI,STPAPIClient.shared().publishableKey iOS Swift UiKit的主要内容,如果未能解决你的问题,请参考以下文章

使用 Stripe,如何为多个客户附加从 Setup Intent API 创建的单一支付方式

如何为 Flutter Web 添加 Firebase 预构建的身份验证 UI?

使用 Try/Catch PHP 方法捕获 Stripe 错误

尽管没有任何错误或异常,为啥 Stripe Google Pay 按钮无法在 UI 上为我呈现?

可以在 VS 包管理器 UI 中显示预发布的 NuGet 包吗?

Rails / Stripe - 付款不会处理