#phiredrop-ios-payment-sheet
1 messages · Page 1 of 1 (latest)
If you make a request to that endpoint from something other than your phone app, do you get the expected data back?
Yes, earlier in the init of my app, I receive my publishable key.
Gotcha, trying to think of what might be happening on the client that is messing up here
👋 stepping in
That's strange
Can you add some logs in Glitch to ensure it is hitting that endpoint correctly?
I'm very new to server side stuff, so I'm not sure how I'd accomplish that
Just add a few console.log("test") within the app.post endpoint
Glitch should provide you a Console at the bottom to see those logs
Okay can you log out the publishable key that you are passing to the client
And make sure it is the correct one
Ah actually hold on
I think I know the issue
Yes in the init, it gets logged and is correct
At least it was yesterday... let me validate now
Ok yes - during init I print the fetched pk and it's valid
Try changing the request.setValue to request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
On your client
And add a line below that for request.httpBody = parameters.data(using: .utf8)
AH wait ignore that sorry
You aren't sending anything to the server here right?
Oh you are
Change parameters to json
Actually that should be fine how it is
Just remove that line
Ahhhh
Sorry I'm all over the place
I actually see the problem
On your client you are handling JSON
it's ok! I really appreciate the extra set of eyes
But you aren't sending JSON from your server
So in Glitch change from res.send to res.json
And ignore what I said to change above
Hmmm can you print data ?
it returns 207 bytes
Your code isn't actually catching this error, no?
Like you don't have an else statement
It is just going to hit that print message no matter what?
Try something like ``` 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 {
let message = error?.localizedDescription ?? "Failed to decode response from server."
self?.displayAlert(title: "Error loading page", message: message)
return
}
print("Created PaymentIntent")
self?.paymentIntentClientSecret = clientSecret
Well it's essentially the same as the demo app here: https://github.com/stripe-samples/accept-a-payment/blob/main/custom-payment-flow/client/ios-swiftui/AcceptAPayment/Model/BackendModel.swift
the else is in the clientSecret let
like it's not finding the client Secret on the Glitch?
No worries
I have it saved in the .env on the Glitch server though, like the instructions say
Is it possible to print data and json after they are initialized?
I can't remember if you can print them within that guard
Hmm,
Huh doesn't seem to like that. Can you print that stuff within the else statement?
Yeah that's where it was working
if you see my screenshot from 10:08 above
If I'm understanding you correctly
Okay sorry let me grab a colleague more familiar with Swift
I just printed json and it returned
["currency": "usd", "paymentMethodType": "card"]
so there isn't a clientSecret that it's returning and assigning to a local constant
Ok dumb question incoming: where does it get the clientSecret from? Because that's not stored in the Xcode project
at least it's not explicitly defined I don't think. I don't see it defined in the example project either
The clientsecret comes from your Server.
So in this case, Glitch
So you create the PaymentIntent on your Server, that creates the paymentIntent.client_secret then you pass that to your client to be able to securely complete the payment.
gotcha
So earlier you had said you had already logged out the publishable key and the client secret, correct?
On your client?
And you were seeing the publishable key?
But did you never actually see the client secret?
that's' correct
Did you set your secret key in Glitch?
Yes they're both there in the .env fields
Okay so can you log out the client secret on your server right before res.json?
So console.log(paymentIntent.client_secret)
Okay so yeah it really does have to be something client side with Swift
Which I'm pretty stumped as everything you have there looks fine
Let me grab my colleague
kk!
hello! reading here one sec
you need to use let paymentIntentClientSecret = json["paymentIntent"] as? String, because you return paymentIntent in your backend code
i.e. because you do
publishableKey: process.env.publishable_key, // https://stripe.com/docs/keys#obtain-api-keys
---> paymentIntent <---: paymentIntent.client_secret,
customer: customer.id,
ephemeralKey: ephemeralKey.secret
});
});
it is json["paymentIntent"] to get that value in the frontend
Hey! That got us a step closer! It printed Created PaymentIntent!
Thank you very much!
The Apple Pay Button is still showing Loading... though from this code:
          if backendModel.paymentIntentParams != nil {
            PaymentButton() {
              applePayModel.pay(clientSecret: backendModel.paymentIntentParams?.clientSecret)
            }
            .padding()
          } else {
            Text("Loading...")
          }```
So it seems like the `paymentIntentParams` isn't properly updated in the screenshot
Although that could be because of my variable change, looking thru it all now
hard to say much with just screenshots of small snippets of parts of the code unfortunately
Happy to host a zoom 🙂
doesn't work that way, but you can share the full text of the ViewController with an issue and point out specific parts that you're having trouble with!
Sure thing. I'll prepare that
if it helps I think https://github.com/stripe-samples/accept-a-payment/tree/1fe2f75631b4e26d004501d5efb1e50d65635e65/custom-payment-flow/client/ios-swiftui/AcceptAPayment is an implementation of those docs in an example project
Yes, I've adapted that into my project
It's been very helpful, and really is just the connection between the client and server that's different that I'm working on ironing out
I have little experience setting up backends, so I'm using the Glitch test server just to get the flow working, then will migrate to something more permanent
Here's the Apple Pay Button code, again pretty much taken from that example:
Here's the Backend Model that we just got it to successfully get the clientSecret:
Right after print("Created PaymentIntent") it should be setting the paymentIntentParams
However the button is showing "Loading" instead of the Apple Pay Button, as if backendModel.paymentIntentParams == nil
unfortunately I've never used SwiftUI so I don't really understand how the async model here(the view updating when the backend model has been updated after the network request) so I'll defer to @long sleet . I don't see anything immediately odd though, the code you posted does look like what we have in the example app
Thank you all so much for the assistance so far!
Even if I remove that check and just show the ApplePay Button, then tap the Apple Pay Button, it crashes the app, so it's definitely more than just an issue updating the view
if it crashes you should have an error message in the XCode console (shift-cmd-c to open that in the Debug Area if it's not open), but overall I'd also be adding print statements throughout the app to see what the values of things are
So that's odd. It indeed is nil even though we're getting the clientSecret
Printing clientSecret does return the pi_xxxxxx
Just checking in. Are there any outstanding questions here?
Hello! Yes the issue of the clientSecret being passed into the paymentIntentParams being nil
hello! I can try and look
Hey awesome!
ah so log out self there, is that nil ? cause you're doing an optional chaining there
(inside the dispatch to main queue)
not sure what self is instantiated as here, assume it is a View Controller or similar (I've done vanilla iOS, not SwiftUI much)
I did log that out in the screeny above right? Or are you looking for a different bit?
oh, I did print(self?.paymentIntentParams) with some extra text in it
just print(self) is fine or rather, breakpoint on the print(clientSecret) line and inspect in the watch window (or the console) what self is then
yep so that's the issue here
you're getting a PaymentIntent client_secret from your server just fine
your app's screen (or view / equivalent) that you're referencing as self is nil here
so you need to look into that
I don't know off hand since it can be a bunch of different reasons
so really, once you identify that, you'll be able to set self.paymentIntentParams = "thing" just fine
in optional chaining, self?.property resolves to nil if self is nil
Hmm. Even creating an AppStorage var of clientSecretKey and setting it to clientSecret returns nil
even though clientSecret is printing with a value. so strange
where are you doing the AppStorage part??
don't see it in the snippet
the snippet seems the same as before
the main issue is just the self?,thing part and that being nil
the clientSecret part is irrelevant for now, since that String is set just fine
you could even replace that with any String like "blah" just for testing, since the actual issue is on the optional part
Just defined it at the top, basically confirming that I'm unable to assign that value to a string. Even doing
self?.paymentIntentParams.clientSecret = clientSecret
returns nil.
So yeah, something with self? that isn't being set properly
Have you checked it self itself resolves to anything? It is sounding like self isn't being initiated
Hmm, well printing self like above, even after receiving the clientSecret, still returns nil for some reason
Do you see where in your code that object is supposed to be initiated? Maybe that isn't being called before the client secret is getting to your app?
Yes, self but like I am assuming there is some broader context where that object is initiated right?
Like in the view's own code it is self but somewhere the view needs to be initialized in other code
Hmm, I don't think so. The source example here doesn't really either I don't think: https://github.com/stripe-samples/accept-a-payment/tree/1fe2f75631b4e26d004501d5efb1e50d65635e65/custom-payment-flow/client/ios-swiftui/AcceptAPayment
Lost track, what file are you in here?
BackendModel.swift
In the example project, it's in Models folder
We're stuck getting self?.paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecret) to actually update with the clientSecret value, even though we are returned a value and it prints fine. For some reason, that paymentIntentParams isn't updating with the value
Hi there 👋 taking over, as my colleague needs to step away
Give me a few minutes to find someone more versed in Mobile development. If there isn't anyone, we may need to have you get ahold of support to start an asynchronous thread
phiredrop-ios-payment-sheet
Ok thank you much! 🙂
Pompey gave me some state, so I was looking at the sample to orient myself. This is the part where you initialize BackendModel as an instance: https://github.com/stripe-samples/accept-a-payment/blob/1fe2f756/custom-payment-flow/client/ios-swiftui/AcceptAPayment/Views/Card.swift#L16
and then make the API call on onAppear() . So my hunch is that something is causing your model instance to get de-initialized, probably by the time you're dispatching to the main thread
don't have a clear one-shot answer cause I'm not the most well versed in SwiftUI (more on vanilla Swift) but that is my read
so my read is, somewhere along the lines, either the Card view is not getting retained, or model is not getting retained
the first thing to try is - clone the same "as is" and try it there and breakpoint on self?.paymentIntentParams and log that out
if that works, then the issue is in how you've adapted the sample into yoru code
that will allow you to identify where the issue lies and approach it
does that help?
Hmm.. So I'm using ApplePay.swift, not Card.swift. Not sure if that makes a difference
although the paymentMethodType being returned says card. hmm
I guess not... they still specify card in the ApplePay.swift
we're talking about diff things
let's start here
cloning the sample
and checking the same flow and what happens there
Do you know how to get the podfiles setup? I've only ever used SPM
I installed it using SPM in my project. That screenshot is the example project
sorry shared the wrong link, I meant to link you to what the samples require: https://github.com/stripe-samples/accept-a-payment/tree/1fe2f75631b4e26d004501d5efb1e50d65635e65/custom-payment-flow/client/ios-swiftui#ios-client
see the readme instructions
I could just use my same glitch server as the example server though yeah?
you might have to change some endpoints or keys in your JSON, if you modified them, but otherwise if you modeled after that, mostly should work the same
kk, got cocoapods installed, running pod install
nice!
Ok, compiled and tested a successful Apple Pay payment on the sample app using my backend Glitch server
Printing the paymentIntentParams?.clientSecret in sample also works
ah good
so that means the sample does work fine, wanted to figure out if there was something wrong in the sample code
now
what you'd need to do is compare the sample's code to your code and see why your View or Model are getting deallocated/losing reference to where by the time you run something on main thread, self becomes nil
another way to do this would be to replace the sample's code with your code bit by bit until you can get it running fully. Or you hit the error but then you know which change caused the error and troubleshoot there
recommend doing that since there's an issue with your code, just hard to pinpoint what. It isn't related to Stripe specifically either, just a general Swift/iOS code issue where something that is being referenced has become nil by the time it is being referenced
Yes this will help with pinpointing it hopefully. Thanks so much