【发布时间】:2021-07-08 16:46:50
【问题描述】:
我正在尝试确认由我的后端 api 生成的 setupintent,但我认为它会尝试多次提交 setupintent。以下方法用于使用 Stripe iOS SDK(不幸的是为 uikit 制作)向用户添加新卡。我调整了示例方法并将它们包装在一些 uiviewrepresentables 中,以便在必要时可以使用 3DS 弹出窗口。问题是它在 Stripe 中得到了验证。 SetupIntent 出现在日志中,但应用程序崩溃。我将在下面为其他可能在 Swiftui 上实现 Stripe SDK 遇到困难的人分享我的代码。
这是我使用 STPPaymentMethod 参数检索并确认 setupintent 的一段代码:
struct FakeStripeView: UIViewControllerRepresentable {
@EnvironmentObject var navView : NavView
@Binding var cardParams : STPPaymentMethodCardParams
@Binding var isActive : Bool
@Binding var billing : STPPaymentMethodBillingDetails
public typealias UIViewControllerType = FakeStripeViewController
func makeUIViewController(context: UIViewControllerRepresentableContext<FakeStripeView>) -> FakeStripeViewController {
let viewController = FakeStripeViewController(navView: navView)
return viewController
}
func updateUIViewController(_ uiViewController: FakeStripeViewController, context _: UIViewControllerRepresentableContext<FakeStripeView>) {
if navView.isActive{
uiViewController.createSetupIntent(cardParams: cardParams, billing: billing, completion: { state in
if state != false{
self.navView.isActive = false
self.navView.addNewCard = false
}
})
}
}
}
class FakeStripeViewController: UIViewController {
var navView: NavView?
convenience init() {
self.init(navView: nil)
}
init(navView: NavView?) {
self.navView = navView
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func createSetupIntent(cardParams: STPPaymentMethodCardParams, billing: STPPaymentMethodBillingDetails, completion: @escaping (Bool) -> ()) {
StripeAPIClient.shared.createSetupIntent(completion: { (setupIntent) in
if(setupIntent.status != "not completed"){
if(setupIntent.status.contains("error:")){
print(setupIntent.status)
}
else{
let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: billing, metadata: nil)
let setupIntentParams = STPSetupIntentConfirmParams(clientSecret: setupIntent.client_secret)
setupIntentParams.paymentMethodParams = paymentMethodParams
let paymentHandler = STPPaymentHandler.shared()
paymentHandler.confirmSetupIntent(setupIntentParams, with: self) { status, setupIntent, error in
switch (status) {
case .failed:
// Setup failed
break
case .canceled:
// Setup canceled
break
case .succeeded:
print("successful")
StripeAPIClient.shared.retrievePaymentMethods()
completion(true)
self.navView?.isActive = false
self.navView?.addNewCard = false
break
@unknown default:
fatalError()
break
}
}
}
}
})
}
}
extension FakeStripeViewController: STPAuthenticationContext {
func authenticationPresentingViewController() -> UIViewController {
self
}
}
这是卡片字段的包装器:
struct StripePaymentCardTextField: UIViewRepresentable {
@Binding var cardParams: STPPaymentMethodCardParams
@Binding var isValid: Bool
@Binding var billing : STPPaymentMethodBillingDetails
func makeUIView(context: Context) -> STPPaymentCardTextField {
let input = STPPaymentCardTextField()
input.borderColor = getColorFromHex(hex: 0x7653DB, alpha: 1.0)
input.borderWidth = 5
input.cornerRadius = 15
input.delegate = context.coordinator
return input
}
func makeCoordinator() -> StripePaymentCardTextField.Coordinator { Coordinator(self) }
func updateUIView(_ view: STPPaymentCardTextField, context: Context) { }
class Coordinator: NSObject, STPPaymentCardTextFieldDelegate {
var parent: StripePaymentCardTextField
init(_ textField: StripePaymentCardTextField) {
parent = textField
parent.billing.email = UserData.shared.user?.email
parent.billing.name = UserData.shared.user?.name
parent.billing.phone = UserData.shared.user?.phone
}
func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) {
parent.cardParams = textField.cardParams
parent.isValid = textField.isValid
parent.billing.address?.postalCode = textField.postalCode
}
}
}
这是添加支付方式的视图。在这个视图中,fakestripeview 被实现,因此我们可以在需要时弹出 3ds。
struct AddPaymentMethod: View {
@State var cardParams : STPPaymentMethodCardParams = STPPaymentMethodCardParams()
@State var billingParams : STPPaymentMethodBillingDetails = STPPaymentMethodBillingDetails()
@State var isValid = false
@EnvironmentObject var navView : NavView
@State var showAlert = false
var body: some View {
VStack(alignment: .center){
CCView(cardParams: $cardParams)
.padding(.leading,10)
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: UIScreen.main.bounds.width/2)
.padding(.bottom)
StripePaymentCardTextField(cardParams: $cardParams, isValid: $isValid, billing: $billingParams)
.frame(height:70)
.padding()
Button(action: {
if(isValid){
navView.isActive = true
}
else{
self.showAlert = true
}
}, label: {
Text("Submit")
.foregroundColor(.white)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(beatactViolet)
.modifier(EventCardModifier())
.padding()
})
Spacer()
FakeStripeView(cardParams: $cardParams, isActive: $navView.isActive, billing: $billingParams)
.frame(width: 0, height: 0).environmentObject(NavView.shared)
}.alert(isPresented: $showAlert, content: {
Alert(title: Text("Card/Adress Invalid"), message: Text("Please try again."), dismissButton: .default(Text("OK!")))
}).navigationTitle("Add card")
}
}
我认为这种方法的主要问题是 fakestripeview 和 AddPaymentMethod 视图的方法之间的接口。如果它对您有任何帮助,请随时使用任何此代码。我知道我花了一段时间才想出一个可行的方法来做到这一点。这种方法有效,但在确认 setupintent 后,它会使应用程序崩溃(但至少它以条带显示)。关于我如何能够改进这一点并使其发挥作用的任何线索?
【问题讨论】:
标签: ios swift swiftui stripe-payments