在 SwiftUI 应用程序上使用 Stripe Payments 与后端服务器通信时出现问题

问题描述 投票:0回答:1
我有一个使用 Stripe Payments 的应用程序,它使用一个名为 StripePaymentView 的视图,允许用户在应用程序上创建 Stripe Payment,只要从 WindowGroup 中的初始结构 MySwiftUIApp: App 文件调用 StripePaymentView,它就可以很好地工作,如下所示

import SwiftUI import SwiftData import Stripe @main struct MySwiftUIApp: App { var body: some Scene { WindowGroup { StripePaymentView() //ContentView() /* ResponsiveView {properties in MainTabbedView(layoutProperties: properties) .modelContainer(for: SavedFavBooksFromISBNDB.self) } .onOpenURL { incomingURL in let stripeHandled = StripeAPI.handleURLCallback(with: incomingURL) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } }*/ } } }
代码有效,因为当我查看运行express.js脚本的后端服务器上的调试控制台时,我可以看到创建了正确金额的付款意图,如下所示

{paymentIntentID: 'pi_3PxEmnJ15oFjjfNB10B4Cm8o', amount: 7744}
但是,当我尝试从应用程序中必须放置视图“StripePaymentView”的任何其他子视图推送视图“StripePaymentView”时,在与后端服务器通信时出现错误。

这是后端服务器上的调试控制台错误

enter image description here

下面是StripePaymentView的代码

import SwiftUI import StripePaymentSheet struct StripePaymentView: View { @FocusState var textFieldFocused: Bool @ObservedObject var model = StripePaymentHandler() @State private var enteredNumber = "" var enteredNumberFormatted: Double { return (Double(enteredNumber) ?? 0) / 100 } var body: some View { VStack { Text("Enter the amount") ZStack(alignment: .center) { Text("$\(enteredNumberFormatted, specifier: "%.2f")").font(Font.system(size: 30)) TextField("", text: $enteredNumber, onEditingChanged: { _ in model.paymentAmount = Int(enteredNumberFormatted * 100) }, onCommit: { textFieldFocused = false }).focused($textFieldFocused) .keyboardType(.numberPad) .foregroundColor(.clear) .disableAutocorrection(true) .accentColor(.clear) } Spacer() if let paymentSheet = model.paymentSheet, !textFieldFocused { PaymentSheet.PaymentButton( paymentSheet: paymentSheet, onCompletion: model.onPaymentCompletion ) { payButton } } } .alert(model.alertText, isPresented: $model.showingAlert) { Button("OK", role: .cancel) { } } .onChange(of: textFieldFocused) { if !textFieldFocused { DispatchQueue.global(qos: .background).sync { model.updatePaymentSheet() } } } .onAppear { model.preparePaymentSheet() } .padding(.horizontal) .padding(.top, 50) .padding(.bottom) .toolbar { ToolbarItem(placement: .keyboard) { Button("Done") { textFieldFocused = false } } } } @ViewBuilder var payButton: some View { HStack { Spacer() Text("Pay $\(enteredNumberFormatted, specifier: "%.2f")") Spacer() } .padding() .foregroundColor(.white) .background( RoundedRectangle(cornerRadius: 10, style: .continuous) .fill(.indigo) ) } }
以及与后端通信的 StripePaymentHandler 代码

import StripePaymentSheet import SwiftUI class StripePaymentHandler: ObservableObject { @Published var paymentSheet: PaymentSheet? @Published var showingAlert: Bool = false private let backendtUrl = URL(string: "http://18.XXX.XX.XX:3000")! private var configuration = PaymentSheet.Configuration() private var clientSecret = "" private var paymentIntentID: String = "" var alertText: String = "" var paymentAmount: Int = 0 func preparePaymentSheet() { // MARK: Fetch the PaymentIntent and Customer information from the backend let url = backendtUrl.appendingPathComponent("prepare-payment-sheet") var request = URLRequest(url: url) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerEphemeralKeySecret = json["ephemeralKey"] as? String, let clientSecret = json["clientSecret"] as? String, let paymentIntentID = json["paymentIntentID"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } self.clientSecret = clientSecret self.paymentIntentID = paymentIntentID STPAPIClient.shared.publishableKey = publishableKey // MARK: Create a PaymentSheet instance configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret) configuration.allowsDelayedPaymentMethods = true configuration.applePay = .init( merchantId: "merchant.com.your_app_name", merchantCountryCode: "US" ) configuration.returnURL = "your-app://stripe-redirect" }) task.resume() } func updatePaymentSheet() { DispatchQueue.main.async { self.paymentSheet = nil } let bodyProperties: [String: Any] = [ "paymentIntentID": paymentIntentID, "amount": paymentAmount ] let url = backendtUrl.appendingPathComponent("update-payment-sheet") var request = URLRequest(url: url) request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try? JSONSerialization.data(withJSONObject: bodyProperties) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let self = self else { // Handle error return } DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret: self.clientSecret, configuration: self.configuration) } }) task.resume() } func onPaymentCompletion(result: PaymentSheetResult) { switch result { case .completed: self.alertText = "Payment complete!" case .canceled: self.alertText = "Payment canceled!" case .failed(let error): self.alertText = "Payment failed \(error.localizedDescription)" } showingAlert = true } }
这是在后端服务器上运行的express.js脚本

const stripe = require('stripe')('sk_test_XXXX'); const express = require('express'); const app = express(); app.use(express.json()); app.post('/prepare-payment-sheet', async (req, res) => { const customer = await stripe.customers.create(); const ephemeralKey = await stripe.ephemeralKeys.create({customer: customer.id}, {apiVersion: '2024-04-10'}); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: customer.id, automatic_payment_methods: { enabled: true, }, }); res.json({ paymentIntentID: paymentIntent.id, clientSecret: paymentIntent.client_secret, ephemeralKey: ephemeralKey.secret, customer: customer.id, publishableKey: 'pk_test_XXXXX' }); }); app.post('/update-payment-sheet', async (req, res) => { const paymentIntent = await stripe.paymentIntents.update( req.body.paymentIntentID, { amount: req.body.amount, } ); console.log(req.body) console.log(res.body) res.json({}); }); app.listen(3000, () => console.log('Running on port 3000'));
    
ios express swiftui stripe-payments
1个回答
0
投票
对于任何可能有帮助的人,我必须更改 @ObservedObject var model = StripePaymentHandler() 到 StripePaymentView 中的 @StateObject var model = StripePaymentHandler() ,不知道为什么它会起作用!

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