#mikep-applepay-ios

1 messages ยท Page 1 of 1 (latest)

spare timber
#

what does "we have apple pay elsewhere" mean? Same app? What's different in the code between the two if so?

pliant kernel
#

Yes, within the same app. We have 2 different checkout styles, each with their own checkout model. So 2 different objects conforming to STPApplePayContextDelegate. The code is largely the same, main difference being one is fetching the secret ahead of time, and the new one is fetching inside the didCreatePaymentMethod like the docs show here: https://stripe.com/docs/apple-pay

#

Ive also tried injecting the secret ahead of time into this new model, but it didn't make a difference.

ornate remnant
#

Hello! Can you share the code from your STPApplePayContextDelegate method implementations that are producing the error?

#

And the code where you create an instance of STPApplePayContext and call presentApplePay on it?

pliant kernel
#

final class StripeApplePayController: NSObject, STPApplePayContextDelegate {

    private var cartId = ""
    private let checkoutService = CheckoutService()

    typealias StripeApplePayCompletionBlock = (STPPaymentStatus, Error?) -> Void
    private var completion: StripeApplePayCompletionBlock?

    func startApplePay(paymentSummaryItems: [PKPaymentSummaryItem], cartId: String, completion: @escaping StripeApplePayCompletionBlock) {
        self.cartId = cartId
        self.completion = completion

        let paymentRequest = StripeAPI.paymentRequest(
            withMerchantIdentifier: StripeApplePayController.merchantIdentifier,
            country: StripeApplePayController.country,
            currency: StripeApplePayController.currency
        )

        paymentRequest.paymentSummaryItems = paymentSummaryItems
        paymentRequest.merchantCapabilities = .capabilityCredit

        if let applePayContext = STPApplePayContext(paymentRequest: paymentRequest, delegate: self) {
            applePayContext.presentApplePay()
        }
    }

    func applePayContext(_ context: STPApplePayContext, didCreatePaymentMethod paymentMethod: STPPaymentMethod, paymentInformation: PKPayment, completion: @escaping STPIntentClientSecretCompletionBlock) {
        checkoutService.fetchCartPaymentIntentClientSecret(cartId: cartId) { result in
            switch result {
            case .success(let secret):
                completion(secret, nil)
            case .failure(let error):
                completion(nil, error)
            }
        }
    }

    func applePayContext(_ context: STPApplePayContext, didCompleteWith status: STPPaymentStatus, error: Error?) {
        self.completion?(status, error)
    }
}
#

(I removed my static variables used in the payment request before I pasted)

ornate remnant
#

That looks correct. Can you share the code where you're creating an instance of this class and calling startApplePay?

pliant kernel
#

yup, heres the code from the view model: ```
private let applePayController = StripeApplePayController()

func payWithApplePay(cartId: String, completion: @escaping (STPPaymentStatus, Error?) -> Void) {
    var summaryItems = [PKPaymentSummaryItem]()
    summaryItems.append(PKPaymentSummaryItem(label: "Estimated Total", amount: NSDecimalNumber(value: Double(round(100*estimatedTotal)/100))))
    summaryItems.append(PKPaymentSummaryItem(label: StripeApplePayController.companyName, amount: NSDecimalNumber(value: Double(round(100*estimatedTotal)/100))))

    applePayController.startApplePay(paymentSummaryItems: summaryItems, cartId: cartId) { status, error in
        completion(status, error)
    }
}
#

and then the code from the view: ```
Button {
guard let cartId = cartDataStore.cartId else { return }
model.payWithApplePay(cartId: cartId, completion: applePayHandler(status:error:))
} label: {
// Apple Pay Button Style takes care of the label
}
.frame(height: 42)
.buttonStyle(ApplePayButtonStyle(paymentButtonType: .buy))

ornate remnant
#

Hm, interesting. You said this works in the simulator... what version of iOS in the simulator? What version of iOS on device?

pliant kernel
#

iOS 15 on both

ornate remnant
#

I honestly don't know what's wrong or why it would fail like that without any errors. Really strange that applePayContext(_:didCompleteWith:error:) isn't being called.

#

The error happens after you confirm the payment with Touch/Face ID, right?

pliant kernel
#

yup, double click side button to confirm, scans face, and then payment not completed from the apple pay sheet but no errors from any of the callbacks

#

almost immediately

ornate remnant
#

Can you share your applePayHandler code?

pliant kernel
#

sure, I think its mostly just view configuration though: ```
private func applePayHandler(status: STPPaymentStatus, error: Error?) {
switch status {
case .success:
navLinkDestination = .confirmation
navLinkActive = true
case .error:
self.cartUpdateError = CheckoutError.unableToProcessYourPayment.description
Log.e(error?.localizedDescription ?? CheckoutError.unableToProcessYourPayment.description)
case .userCancellation:
return
}
}

ornate remnant
#

Have you tried adding a line at the top of that function that logs both status and error?

#

Or even just to log a THIS CODE RAN string just to confirm it's not getting called?

pliant kernel
#

ill try that now

#

didnt hit

ornate remnant
pliant kernel
#

I have a breakpoint on didCompleteWith in the model and that hasnt hit either

#

sure, let me give that a go

#

that worked

ornate remnant
#

Okay, so that works, it works in another part of your app, it just doesn't work in this particular place, correct?

pliant kernel
#

yeah

ornate remnant
#

๐Ÿค”

pliant kernel
#

AND it works on the simulator

ornate remnant
#

Right.

#

Two more ideas:

pliant kernel
#

(also, ty in advance for your help. I really appreciate it.)

ornate remnant
#
  1. Can you log StripeApplePayController.merchantIdentifier and confirm it's set to the expected value just before you use it to initialize STPApplePayContext?
#
  1. Restart the iOS device and try again.
pliant kernel
#

sure let me try those now

#

okay merchant id looks right, ill try restarting but I had a colleague test on their device also and it didnt work for them either

#

same behavior

ornate remnant
#

Ah, okay.

pliant kernel
#

also other bit of info, im using the same merchant id across 2 different targets, but I think that should be okay?

#

it works for our other checkout flow with the same merchant id

ornate remnant
#

That should be fine.

#

Wondering if the Apple Pay entitlement is wonky.

#

A colleague mentioned this a while ago:

Apple Pay on simulator works without explicitly enabling the entitlement but to run on device, you need the entitlement and the merchant ID selected in Xcode when you build to device.

pliant kernel
#

hmm redacting all that might be a bit difficult, could I dm it to you?

ornate remnant
#

I have DMs disabled, but can you check and see if the entitlement is enabled and looks correct?

pliant kernel
#

both targets look like this

#

and im on XCode 13

ornate remnant
pliant kernel
#

okay ty again

#

i found it

#

this line: paymentRequest.merchantCapabilities = .capabilityCredit

#

if i remove that it works

ornate remnant
#

๐Ÿ˜ฑ

#

I... what? ๐Ÿ˜„

pliant kernel
#

....hahah

ornate remnant
#

I'm glad you got it working! I'm going to have to research why that's the case later though, as that is not what I would expect!

pliant kernel
#

what a relief haha

#

thanks again for all your help

ornate remnant
#

No problem, have a great day!

pliant kernel
#

you too!

ornate remnant
#

Dropped this in our internal chat to investigate later and my teammate mentioned this:

Dropping this here before I move on - did some quick googling, it sounds like for those capabilities (https://developer.apple.com/documentation/passkit/pkmerchantcapability). capability3DS is required. I wonder if removing the line all together sets it to some default that includes capability3DS and makes it work?

Seems plausible?

pliant kernel
#

ah so are you thinking paymentRequest.merchantCapabilities = [.capability3DS, .capabilityCredit] should work? I can test that in a little bit and let you know

ornate remnant
#

It might, yeah. Worth testing I think!

pliant kernel
#

yup, that worked!