使用 Stripe 的 ApplePay 中的无效地址

Invalid Address in ApplePay with Stripe

我在 Stripe 上使用 Apple Pay,在没有送货服务的情况下它工作正常。

选择了一个运输地址时,它总是会出现无效的地址错误。 (与 Stripe Sandbox Key 配合使用)

我正在使用 STKPaymentContext API 并按照以下 link.

中的步骤操作

https://stripe.com/docs/mobile/ios/basic

在配置里,我写了这个

let config = STPPaymentConfiguration.shared()
config.requiredShippingAddressFields = [.postalAddress, .phoneNumber,.name]

不确定这里有什么问题。

这是它的样子。

这是我的代码

extension CheckoutTableViewController:STPPaymentContextDelegate{
    
    func paymentContext(_ paymentContext: STPPaymentContext, didUpdateShippingAddress address: STPAddress, completion: @escaping STPShippingMethodsCompletionBlock) {
        
        guard
            let buyerPostalCode = address.postalCode,
            let buyerCountry = address.country,
            let productId = self.productDetailsData?.productId
            else{
            completion(.invalid, nil, nil, nil)
            return
        }
        
        guard let phone = address.phone, phone.count > 0 else {
            completion(.invalid,RatesError.phoneNumberRequired,[],nil)
            return
        }
        
        var shipmentItem:[String:Any] = [:]
        shipmentItem["order_amount"] = self.productCost
        shipmentItem["actual_weight"] = 8
        shipmentItem["height"] = 7
        shipmentItem["width"] = 10
        shipmentItem["length"] = 13
        shipmentItem["currency"] = "USD"
        shipmentItem["destination_postal_code"] = buyerPostalCode
        shipmentItem["destination_country_code"] = buyerCountry
        shipmentItem["product_id"] = productId
        shipmentItem["category"] = "fashion"
      
        enum RatesError:Error,LocalizedError{
            case NoDeliveryOptionsFound
            case phoneNumberRequired
            public var errorDescription: String? {
                switch self {
                case .NoDeliveryOptionsFound:
                    return "No couriers are available at the address.\nPlease try with different address."
                case .phoneNumberRequired:
                    return "Please enter phone number."
                }
            }
        }
        
        fetchShippingOptions(forItem: shipmentItem, completionSuccess: {[weak self] (response) in
            
            guard let self = `self` else {
                return
            }
            
            if
                let responseValue = response as? [String:Any],
                let rates = responseValue["rates"] as? [[String:Any]]{
                self.shippingRates = []
                for rate in rates{
                    if let fullName = rate["courier_display_name"] as? String,
                        let identifier = rate["courier_id"] as? String,
                        let amount = rate["shipment_charge_total"] as? Double,
                        let detail = rate["full_description"] as? String
                    {
                    
                        let method = PKShippingMethod()
                        method.amount = NSDecimalNumber.init(value: amount.currency)
                        method.identifier = identifier
                        method.label = fullName
                        method.detail = detail.replacingOccurrences(of: fullName, with: "")
                        self.shippingRates.append(method)
                    }
                }
                completion(.valid, nil, self.shippingRates, self.shippingRates.first)
            }else{
                completion(.invalid,RatesError.NoDeliveryOptionsFound,[],nil)
            }
        }) { (error) in
            completion(.invalid,error,[],nil)
        }
    }
    
    func paymentContextDidChange(_ paymentContext: STPPaymentContext) { 
        if let paymentOption = paymentContext.selectedPaymentOption {
            self.lblPaymentMethod.text = paymentOption.label
        } else {
            self.lblPaymentMethod.text = "Select Payment"
        }
        if let shippingMethod = paymentContext.selectedShippingMethod {
            if let selectedRate = self.shippingRates.first(where: { (method) -> Bool in
                guard let leftValue = method.identifier, let rightValue = shippingMethod.identifier else{
                    return false
                }
                return leftValue == rightValue
            }){
                self.lblAddress.text = selectedRate.label
                self.shippingCharges = Double(truncating: selectedRate.amount).currency
                self.lblShippingCharges.text = "$\(shippingCharges)"
                self.getStripeFees(forAmount: self.productCost + self.shippingCharges)
            }
        } else {
            self.lblAddress.text = "Select Address"
        }
        
        self.updateTotalCost()
    }
    
    func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) {
        let alertController = UIAlertController(
            title: "Error",
            message: error.localizedDescription,
            preferredStyle: .alert
        )
        let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
            // Need to assign to _ because optional binding loses @discardableResult value
            // https://bugs.swift.org/browse/SR-1681
            _ = self.navigationController?.popViewController(animated: true)
        })
        let retry = UIAlertAction(title: "Retry", style: .default, handler: { action in
            self.paymentContext?.retryLoading()
        })
        alertController.addAction(cancel)
        alertController.addAction(retry)
        self.present(alertController, animated: true, completion: nil)
    }
    
    func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPPaymentStatusBlock) {
        self.callPaymentIntentAPI(paymentContext, didCreatePaymentResult: paymentResult, completion: completion)
    }
    
    func paymentContext(_ paymentContext: STPPaymentContext, didFinishWith status: STPPaymentStatus, error: Error?) {
        OperationQueue.main.addOperation {
            SVProgressHUD.dismiss()
        }
        let title: String
        let message: String
        switch status {
        case .error:
            title = "Error"
            message = error?.localizedDescription ?? ""
            UIAlertController.showAlert(withTitle: title, andMessage: message, andButtonTitles: ["Okay"]) {[weak self] (selectedIndex) in
                OperationQueue.main.addOperation {
                    self?.navigationController?.popViewController(animated: true)
                }
            }
        case .success:
            title = "Success"
            message = "Your purchase was successful!"
            UIAlertController.showAlert(withTitle: title, andMessage: message, andButtonTitles: ["Okay"]) {[weak self] (selectedIndex) in
                OperationQueue.main.addOperation {
                    self?.onPaymentCompletion?()
                    var isControllerFound:Bool = false
                    for controller in self?.navigationController?.viewControllers ?? []{
                        if (controller is ProductDetailsViewController) || (controller is ChatVC){
                            isControllerFound = true
                            self?.navigationController?.popToViewController(controller, animated: true)
                            break
                        }
                    }
                    if !isControllerFound{
                        self?.navigationController?.popViewController(animated: true)
                    }
                }
            }
        case .userCancellation:
            return()
        @unknown default:
            return()
        }
    }
}

终于发现错误了

Apple 在付款时调用 didUpdateShippingAddress 方法,但出于安全目的,它并未提供所有信息。所以在我的例子中 phone 数字验证导致了这个错误。

所以我从该方法中删除了以下代码。

    guard let phone = address.phone, phone.count > 0 else {
        completion(.invalid,RatesError.phoneNumberRequired,[],nil)
        return
    }