#squidonomics

1 messages · Page 1 of 1 (latest)

rough hornetBOT
smoky bone
#

Hello

#

Hmmm not really a good reason I can think of

#

What does "not show up" entail?

#

Like you are pressing the button to present the Payment Sheet but nothing happens?

frozen gyro
#

yes exactly that

#

it's stuck in loading state

#

the button never enables

smoky bone
#

Hrmmm have you hooked up the device to your Mac and run the debugger for it?

frozen gyro
#

I have

#

I've done breakpoint testing and everything

smoky bone
#

And you don't see anything in those logs?

frozen gyro
#

no, the create payment intent, ephemeral key and customer are created on stripe servers

smoky bone
#

Have you added some logs to ensure all the proper config and client secret is present for Payment Sheet?

frozen gyro
#

and it shows up in stripe logs as well

smoky bone
#

Okay so you are successfully hitting your server, that's good.

#

Is the server responding to your app successfully?

frozen gyro
#

yes, the returned values all appear when debugging variables

#

and they match the values returned in stripe logs for that request

smoky bone
#

Hmmm

#

Can you provide a video capture of what is happening on your device exactly?

frozen gyro
#

on both the emulator and the real phone?

smoky bone
#

No just the real phone

frozen gyro
#

Yes, one second

#

Button(action: { model.preparePaymentSheet() }){                 Text("Pay")                     .frame(width: 250, height: 50, alignment: .center)                     .background(Color(red: 15/255.0, green: 35/255.0, blue: 101/255))                     .foregroundColor(Color.white)                 }                 VStack{                 if let paymentSheet = model.paymentSheet {                     PaymentSheet.PaymentButton(                       paymentSheet: paymentSheet,                       onCompletion: model.onCompletion                     ) {                       Text("Buy")                     }                   } else {                     Text("Loading…")                   }                   if let result = model.paymentResult {                     switch result {                     case .completed:                       Text("Payment complete")                     case .failed(let error):                       Text("Payment failed: \(error.localizedDescription)")                     case .canceled:                       Text("Payment canceled.")                     }                   }                 }         }.onAppear { model.preparePaymentSheet() }

#

pressing the button and onAppear are used to test the ability to get the sheet to appear

#

neither of which work for some reason

smoky bone
#

Thanks looking

#

While I look can you also take a quick screen cap of the emulator actually with the same flow

#

That would be helpful

#

So you set a breakpoint in model.paymentSheet, correct?

frozen gyro
#

I set my breakpoints inside the backend function. I can test them on model.paymentSheet too

#

emulator

smoky bone
#

Oh yeah this isn't a backend issue I don't think

#

Wait wait wait

#

You are hitting a different button on your emulator

#

You are hitting "Buy" instead of "Pay"

frozen gyro
#

buy auto loads because of the onAppear function

#

when it doesn't load I use the button "Pay" to preparePaymentIntent

smoky bone
#

Oooooh k that is different lol

#

So you aren't getting your "Buy" button to show, it isn't that PaymentSheet isn't presenting

frozen gyro
#

yes, when buy shows the sheet presents but for some reason the real phone just doesn't pass the if let condition

smoky bone
#

Can you recreate the state on your emulator where you have "loading..." and hit "Pay"?

#

And to clarify, you said above, you already added logs to your iOS app here for the client secret?

frozen gyro
#

I can't which is crazy. I've tried removing on appear and removing weak self but nothing

#

yes, debugging client secret returns the value stripe logs says they've sent

smoky bone
#

What is the code for the "Pay" button?

#

Like you are using that to hit your server, correct?

frozen gyro
#

yes

smoky bone
#

Can you share that code?

frozen gyro
#

Button(action: { model.preparePaymentSheet() }){                         Text("Pay")                             .frame(width: 250, height: 50, alignment: .center)                             .background(Color(red: 15/255.0, green: 35/255.0, blue: 101/255))                             .foregroundColor(Color.white)                         }

#

nothing fancy just preparing the sheet

smoky bone
#

And the full task code

#

Also just so you know, you can use three ` to share code more cleanly

#

Like this

frozen gyro
#
                        Text("Pay")
                            .frame(width: 250, height: 50, alignment: .center)
                            .background(Color(red: 15/255.0, green: 35/255.0, blue: 101/255))
                            .foregroundColor(Color.white)
                      }```
smoky bone
#

👍

frozen gyro
#

ahh thank you

#

the preparePaymentSheet function?

smoky bone
#

No probs. Can you dump all the relevant code to hitting your server here. Yep that function

frozen gyro
#
    // MARK: Fetch the PaymentIntent and Customer information from the backend
    var request = URLRequest(url: backendCheckoutUrl)
    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 paymentIntentClientSecret = json["paymentIntent"] as? String,
                  let publishableKey = json["publishableKey"] as? String,
                  let self = self else {
    
                return
            }

            STPAPIClient.shared.publishableKey = publishableKey
            // MARK: Create a PaymentSheet instance
            var configuration = PaymentSheet.Configuration()
            configuration.merchantDisplayName = "Test Company"
            configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret)
            configuration.allowsDelayedPaymentMethods = true

            DispatchQueue.main.async {
                
              self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration)
            }
          })
          task.resume()
  }
    
    func onCompletion(result: PaymentSheetResult) {
            self.paymentResult = result

            if case .completed = result {
                self.paymentSheet = nil
                preparePaymentSheet()
            }
        }
}```
smoky bone
#

K let's add a bunch of logs just to double check. Can you add a print like:

    print("ERROR HERE!")
                return
            }

And then let's log out your key:

print("pub key: ", publishableKey)```
And ``` DispatchQueue.main.async {
                print("clientsecret: ", paymentIntentClientSecret)
              self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration)```
#

Then run a test and let's see what your XCode console shows

frozen gyro
#

the error occurs on self

smoky bone
#

Okay that helps

frozen gyro
#

I can show you the breakpoint print content if you need it

smoky bone
#

Oops

#

I forgot that should actually return an error!

#

Let's just print that error

#

print("ERROR HERE! ", error)

#

Err wait no

#

The error would before

#

on task

frozen gyro
#

error will print nil there

smoky bone
#

Yeah

frozen gyro
#

oh on task okay

smoky bone
#

Like we want the error from let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error)

#

So I think you need a try/catch here

frozen gyro
#

my thought was put a do right above the task then catch at the end?

#

but it looks like that won't be it

smoky bone
#

I'm not that familiar with iOS code tbh... can you just print the error in the guard?

#

Hmm no I really think it should be in the else block

#

Like in my sample I have: else { let message = error?.localizedDescription ?? "Failed to decode response from server." self?.displayAlert(title: "Error loading page", message: message) return }

#

So if you are getting null there then the issue is indeed how you are receiving the data from the server.

#

Can you show me your server code?

#

How are you sending the data back?

frozen gyro
#

I am adding in that error code to test it

#

ahh

smoky bone
#

Sounds good. It likely will just show you "Failed to decode response from server."

frozen gyro
#

yep

smoky bone
#

What device are you testing on?

frozen gyro
#


app.post('/payment-sheet', async (req, res) => {
  // Use an existing Customer ID if this is a returning customer.
  const customer = await stripe.customers.create();
  const ephemeralKey = await stripe.ephemeralKeys.create(
    {customer: customer.id},
    {apiVersion: '2022-08-01'}
  );
  const paymentIntent = await stripe.paymentIntents.create({
    amount: 1099,
    currency: 'eur',
    customer: customer.id,
    automatic_payment_methods: {
      enabled: true,
    },
  });

  res.json({
    paymentIntent: paymentIntent.client_secret,
    ephemeralKey: ephemeralKey.secret,
    customer: customer.id,
    publishableKey: 'key'
  });
}); ```
#

I've tested on an iPhone 11 and iPhone 13

smoky bone
#

Ah actually

#

Maybe we should just try printing the response

#

That would be first step

#

Didn't realize we hadn't done that yet

#

In your else block let's print("response: ", response)

#

Then dump that payload

frozen gyro
#
    Connection =     (
        "keep-alive"
    );
    "Content-Length" =     (
        347
    );
    "Content-Type" =     (
        "application/json; charset=utf-8"
    );
    Date =     (
        "Fri, 14 Oct 2022 19:15:08 GMT"
    );
    Etag =     (
        "W/\"15b-FLxslPNdhSsyZtKI5uzNwix0FTY\""
    );
    "Keep-Alive" =     (
        "timeout=5"
    );
    "X-Powered-By" =     (
        Express
    );
} })
smoky bone
#

Wat

#

That's super weird

#

Are you sure you are hitting the right endpoint?

#

I mean you said you are seeing the PI created in your Dashboard....

#

So it seems like you are....

frozen gyro
#

yes I can send the stripe logs

#

I get all three created: create payment intent, create emphem key and create customer

smoky bone
#

If you print data in your else block to you get anything?

#

Oh snap

#

You are using HTTP

#

Instead of HTTPS. That might be the issue.

frozen gyro
#

I can test https real quick

smoky bone
#

Yeah give that a try

#

I totally missed that the above does have Content-Length = 347

#

So the body is there

#

So it isn't HTTP that is the issue

frozen gyro
#

I tested https and I get the same thing

#

oh yeah^

smoky bone
#

Don't remember if you can print data in the else block?

#

Will that get carried down?

frozen gyro
#

data just returns the body of the request

#

body size*

smoky bone
#

Oh yeah because we didn't JSONSerialize yet

#

so do ``` let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any],

#

And then print(json)

#

I'm so confused. It seems like everything is there and this is all working fine

#

So maybe I was wrong and this isn't the issue at all

frozen gyro
#

I am too

#

it makes no sense at all

smoky bone
#

Did your pub key ever print?

#

Or it doesn't make it there?

frozen gyro
#

no it never makes it to there

#

I can breakpoint to see the pub key return value

smoky bone
#

Oh right because we are in the else block and then returning

frozen gyro
#

and it's there

#

but yeah the else block stops it from mattering

smoky bone
#

So this does have to be the issue still.... self = self is not working

#

Okay so let's do the above and see what the response body looks like I guess

frozen gyro
#

try and print the json?

smoky bone
#

Yeah

#

Let's just make sure the responseBody looks like it should

frozen gyro
#

putting print right after won't work because condition must be bool

smoky bone
#

Down in else?

frozen gyro
#

json is out of scope

smoky bone
#

Ah okay that's what I wasn't sure about before

#

Let me go grab a colleague more familiar with iOS

#

We might just be missing something too

frozen gyro
#

probably

#

thank you

smoky bone
#

While I do that, instead of trying to log out json directly, can you just do JSONSerialization in the else block?

#

Oh wait no

#

Cause then data is out of scope too right

frozen gyro
#

yes

#

I'm gonna debugprint data

smoky bone
#

When you added your breakpoint you saw your customer/clientsecret/ephkey variables there, correct?

#

You added po in console to log those?

#

Oh yeah apparently you can just do po json

frozen gyro
#
▿ 4 elements
  ▿ 0 : 2 elements
    - key : "paymentIntent"
    - value : pi_3LstroAwKsZ0hizW2xDmsBf8_secret_XDVYn1BAafCSCGeDKONuY3sdC
  ▿ 1 : 2 elements
    - key : "ephemeralKey"
    - value : ek_test_YWNjdF8xS2pxMUtBd0tzWjBoaXpXLHZsZDZ3T2NxYkVJVXBoaGlacVpVdDJTMTdPUW9zMGI_00iNmkmafK
  ▿ 2 : 2 elements
    - key : "customer"
    - value : cus_Mc88Np6026GWiP
  ▿ 3 : 2 elements
    - key : "publishableKey"
    - value : pk_test_51Kjq1KAwKsZ0hizWeuQL1sT3L1u9ZcsITh961jyj7uly6A6aYx2DSduWrZ6kiComgch3q4qsNAF4q0a80rmYCEhl00XBEFRLIx```
#

that's the breakpoint value of json

smoky bone
#

Thanks. Can you also put a breakpoint after self and let's look at what that gets assigned?

frozen gyro
#

nil

#

sorry that was breakpoint on nil

#

let me try it again

#
(relsto.MyNewerBackendModel?) self = 0x0000000280dad980 {
  backendCheckoutUrl = {}
  _paymentSheet = {}
  _paymentResult = {}
  seconds = 7.7182398584174996E-313
}```
smoky bone
#

Okay yeah so that seems wrong. I think paymentSheet shouldn't be a null object here...

frozen gyro
#

I can show you what is returned on the emulator

smoky bone
#

Yeah that is a good idea

#

Ah wait

#

self just might be handling the controller here

#

Still worth comparing

#

But not sure that paymentSheet won't be empty here

frozen gyro
#

it's building

#

from what I remember it's still empty

smoky bone
#

I just can't fathom why we are going into this else block

frozen gyro
#

neither can I

#

I havent found this issue anywhere else on the internet

#

I've checked network traffic, memory usage like everything I can think of

smoky bone
#

Okay my colleague says that the self object should have some reference to your view controller so that likely is why then

#

Let's see what the emulator shows

#

Also have you rebuilt on your actual device at any point?

#

Probably worth ruling out the turn off/turn on approach in case somehow the device just got in a weird state on build

frozen gyro
#

I'll reset my real device right now too

#

just cleaned the build folder to make sure this is how it runs

#

sorry this rebuild is taking forever

smoky bone
#

No worries

frozen gyro
#

okay

#

emulator prints this

#
<MyNewerBackendModel: 0x6000018dc6e0>```
#

actually just hit an interesting bug

#

after hard reseting my real device

#

The build service has encountered an internal inconsistency error: unexpected incomplete target: <ConfiguredTarget target: FirebaseCoreInternal:8699adb1dd336b26511df848a716bd42020791fd2e7b7ddc8fb2658339c42e16> (started: 29, completed: 0)

smoky bone
#

Aha an actual error message finally

#

That said, is that on build?

frozen gyro
#

it looks like its a total build error

#

I am out of build rows so I'm gonna clear it and try again

smoky bone
#

👍

frozen gyro
#

alright it's completely rebuilding on the real iphone 11 now

#

still nothing unfortunately

#

cleaned all folders and rebuilt on both the xcode project and on the deivce

smoky bone
#

Yeah I don't know... try removing the return in your else block and see if it runs?

frozen gyro
#

still nothin

#

well that sucks

#

I guess I'll keep messing around with it. Thanks for your help

smoky bone
#

One sec

#

Okay let's try one more thing

#

Instead of having two buttons here, let's just use the "Pay" button to present the sheet.

#

Can you hook your code up to that button and not mess with the "Loading/Buy" button at all?

frozen gyro
#

okay

#

I'll try tat

#

might take a few minutes

smoky bone
#

Sounds good

frozen gyro
#

I can't seem to put it into a button because it is its own button already

#

the text and how it's designed are the only things I can change

smoky bone
#

What do you mean by that exactly?

#

Payment Sheet really isn't designed for two buttons to begin with

frozen gyro
#
                      paymentSheet: paymentSheet,
                      onCompletion: model.onCompletion
                    ) ```
smoky bone
#

Ah maybe I mixed up the buttons I mentioned above. I mean just unhitch your "Pay" button.

frozen gyro
#

I don't think I can force a payment button that is already designed into another button. I can get rid of the pay button and use only on appear

#

nothing on that either

#

I can't fathom why everything works until the response for a real device but not the emulator

smoky bone
#

You said you tested on two different real devices, yes?

frozen gyro
#

yes

#

an iphone 13 and an iphone 11

smoky bone
#

What iOS SDK version are you on?

frozen gyro
#

15.5

smoky bone
#

And Stripe iOS SDK?

frozen gyro
#

oh for stripe my bad

smoky bone
#

Nah that is helpful too

#

The only real path forward at this point that I can think of is us tryin to repro this from our end

frozen gyro
#

I cannot for the life of me find my sdk version right now

#

the api is 8-21-2022

smoky bone
#

If you look at your Pods folder in the General tab and click on Stripe-Stripe for targets

#

Should show you your SDK version

frozen gyro
#

22.8.1

smoky bone
#

Thanks

frozen gyro
#

22.8.2*

#

no problem. Thanks for the help

smoky bone
#

Going to try and repro with my basic sample. If you want us to dig further you could email our Support team and attach your project that we can use to attempt to repro/debug.

#

But yeah, I'm basically out of ideas at the moment

frozen gyro
#

alright, I will. Thanks for everything that was a long process

#

I'm gonna keep seeing what's happened

smoky bone
#

Built mine on my iPhone 11 with similar code and mine works fine

#

So yeah probably sharing your project would help. Not sure I'll be able to repro otherwise