#squidonomics - ios payment intent
1 messages · Page 1 of 1 (latest)
Hi 👋
Can you share the relevant code snippets? Formatted between three `?
To be clear, I'm not a Swift programmer but I can reach out to my colleagues and double check any syntax or process issues.
As an additional resource, have you checked out the Example iOS apps we have in our iOS Github repo?
https://github.com/stripe/stripe-ios/tree/master/Example
Hello
Here's the two snippets from the tutorial video I followed that work when emulating but not on an actual device
      if let paymentIntent = model.paymentIntentParams {
        Button(action: {payAvail = true; paymentIntent.paymentMethodParams = paymentMethodParams}) {
        Text("Pay")
      }
      .paymentConfirmationSheet(isConfirmingPayment: $payAvail, paymentIntentParams: paymentIntent, onCompletion: model.onCompletion)
      .disabled(payAvail)
      } else {
        Text("Loading...")
      }
      Â
      if let paymentStatus = model.paymentStatus {
        HStack {
          switch paymentStatus {
          case .succeeded:
            Image(systemName: "checkmark.circle.fill").foregroundColor(.green)
            Text("Payment complete!")
          case .failed:
            Image(systemName: "xmark.octagon.fill").foregroundColor(.red)
            Text("Payment failed! \(model.lastPaymentError ?? NSError())")
          case .canceled:
            Image(systemName: "xmark.octagon.fill").foregroundColor(.orange)
            Text("Payment canceled.")
          @unknown default:
            Text("Unknown status")
          }
        }
      }
    }.onAppear{ model.preparePaymentIntent(paymentMethodType: "card", currency: "usd")}  }
      Â
     Â
    }
} ```
  @Published var paymentStatus: STPPaymentHandlerActionStatus?
  @Published var paymentIntentParams: STPPaymentIntentParams?
  @Published var lastPaymentError: NSError?
  var custmamnt = ""
  var paymentMethodType: String?
  var currency: String?
  let feesandtaxes : Double = UserDefaults.standard.double(forKey: "Cost") * 0.03 + 0.30
  func preparePaymentIntent(paymentMethodType: String, currency: String){
    self.paymentMethodType = paymentMethodType
    self.currency = currency
    custmamnt = "\(UserDefaults.standard.string(forKey: "Cost") ?? "")"
    let url = URL(string: backendUrl + "create-payment-intent")!
    let json: [String: Any] = ["items": ["amount": feesandtaxes + 3.00 + UserDefaults.standard.double(forKey: "Cost")]]
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: json)
    let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self]
      (data, response, error) in
      guard let response = response as? HTTPURLResponse,
         response.statusCode == 200,
         let data = data,
         let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
         let clientSecret = json["clientSecret"] as? String else {
        print("uh oh")
        return
      }
      print(request.httpBody)
      DispatchQueue.main.asyncAfter(deadline: DispatchTime(uptimeNanoseconds: 3000000)) {
        self?.paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecret)
      }
    })
    task.resume()
  } ```
      self.paymentStatus = status
      self.lastPaymentError = error
    }
}```
this last function is in the backend model the message was just too long to send together
thank you
What iOS device are you running on? When you say it sends the PI twice are they separate PIs? Or the same being sent twice?
I am running it on a real iphone 11 and an emulated iphone 11
It sends a PI that creates a payment intent and then sends the confirm payment intent with no card information immediately after without accepting my card details on the real iphone
Okay that is different that what I was reading your question as.
Have you tried decoupling your logic with the onAppear hook?
It seems that having onAppear be called twice is a common issue: https://stackoverflow.com/questions/63080830/swifui-onappear-gets-called-twice
It seems you can address this by wrapping the onAppear callback in a conditional to check for this:
.onAppear{
if firstTime{
firstTime = false
self.perform()
}
}
I have tried this
but I havent tried wrapping it
I will put this in right now
squidonomics - ios payment intent
Unfortunately I am still seeing two packets go out
And these two are requests the Create and Confirm requests for the same PI?
currently looking at my logs right now and the second one isn't even hitting stripe servers. I get a response which contains the client secret
however, if let paymentIntent = model.paymentIntentParams
does not enable the button and gets passed onto the else condition
when I emulate an iphone the button does get enabled which is where I am stuck
Yeah that part is confusing me too. I haven't seen an issue where the emulator and devices diverge this much.
If you strip out the Stripe specific code can you replicate this behavior?
no, it only seems to happen with the stripe elements.
I can send and receive requests normally everywhere else
Okay can you tell me what the two requests are? What URLs are they to?
Okay, that URL ins't a Stripe URL. When does it reach out to Stripe?
sorry
"/v1/charges?payment_intent=pi_3LnljSAwKsZ0hizW0DWRITjM"
this is the url on the logs
the difference between the two
But we don't accept URL params in those requests so that seems odd. All parameters are URL form encoded
Response body{ "id": "pi_3LnljSAwKsZ0hizW0DWRITjM", "object": "payment_intent", "amount": 1099, "amount_capturable": 0, "amount_details": { "tip": { } }, "amount_received": 0, "application": null, "application_fee_amount": null, "automatic_payment_methods": { "enabled": true }, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_3LnljSAwKsZ0hizW0DWRITjM" }, "client_secret": "pi_3LnljSAwKsZ0hizW0DWRITjM_secret_hOyTZD8pfXbG3W6TEhMzYAvZr", "confirmation_method": "automatic", "created": 1664553994, "currency": "usd", "customer": null, "description": null, "invoice": null, "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "mandate_options": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "processing": null, "receipt_email": null, "review": null, "setup_future_usage": null, "shipping": null, "source": null, "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_payment_method", "transfer_data": null, "transfer_group": null}
that was response log
Okay and that URL is getting hit twice?
Or are you calling the /v1/pamyment_intents/:id/confirm?
on the emualted device the payment intent is created, the client secret returned and then I can fill out the Stripe form to send card details and it gets confirmed.
with the real ios device I open the same page and the client secret is returned once but network activity shows two packeted being sent. Then if let paymentIntent = model.paymentIntentParams fails
should I call confirm?
but network activity shows two packeted being sent
To what URL?
This difference in behavior is really weird.
Can you try running the Payment Sheet example app in the Example section? And try running it on the iOS device in question?
https://github.com/stripe/stripe-ios/tree/master/Example
they're both to my local server it's just that I only return one client secret and it keeps my button disabled
so I know it goes through
yes one second
Upon checking my server does not respond with the customer id or ephemeral key
could that be the issue with a live device?
I'm not sure if emulated devices are allowed special permission like postman on stripe servers
It would be an issue. The emulated device should not have any different permissions as far as Stripe is concerned. It may be something to do with the iOS device permissions though.
Can you include a logging statement in the preparePaymentIntent function to confirm that function is being called twice?
I will go do that now
Okay great. And how does the Payment Sheet example app run?
I have it to where I'm not sending two requests anymore
the example payment app is doing the same thing right now though
👋
Stepping in as Snufkin needs to step away
You noted above that this is not happening anymore except on the example
Were you able to figure out how to resolve this?
I was able to resolve the double request issue. I am going to get the ephermeral keys and try to see if that allows me to make requests again.
Cool