Shopify / mobile-buy-sdk-ios

Shopify’s Mobile Buy SDK makes it simple to sell physical products inside your mobile app. With a few lines of code, you can connect your app with the Shopify platform and let your users buy your products using Apple Pay or their credit card.
MIT License
452 stars 199 forks source link

Apple Pay delegate methods not being called #960

Closed joshgare closed 5 years ago

joshgare commented 5 years ago

I am trying to implement Apple Pay into my iOS app. I have followed the examples on readme in this repo and the Storefront example app.

I have a BasketViewController that brings up the Apple Pay authorisation sheet with the following code.

    func initiateApplePay(for checkout: CustomCheckout, with controller: BasketViewController) {
        let paySession: PaySession = PaySession(shopName: "TestShop",
                                                checkout: checkout.payCheckout,
                                                currency: PayCurrency(currencyCode: "GBP", countryCode: "GB"),
                                                merchantID: ShopifyClient.merchantID)
        paySession.delegate = self
        paySession.authorize()
    }

I have also implemented the following to ensure BasketViewController conforms to the PaySessionDelegate.

extension BasketViewController: PaySessionDelegate {

    func paySession(_ paySession: PaySession, didRequestShippingRatesFor address: PayPostalAddress, checkout: PayCheckout, provide: @escaping (PayCheckout?, [PayShippingRate]) -> Void) {
        print("Requested shipping rates")
        provide(checkout, [PayShippingRate(handle: "Free", title: "Free", price: 0)])
    }

    func paySession(_ paySession: PaySession, didUpdateShippingAddress address: PayPostalAddress, checkout: PayCheckout, provide: @escaping (PayCheckout?) -> Void) {
        print("Updated shipping address")
        provide(checkout)
    }

    func paySession(_ paySession: PaySession, didSelectShippingRate shippingRate: PayShippingRate, checkout: PayCheckout, provide: @escaping (PayCheckout?) -> Void) {
        print("Selected shipping rate")
        provide(checkout)
    }

    func paySession(_ paySession: PaySession, didAuthorizePayment authorization: PayAuthorization, checkout: PayCheckout, completeTransaction: @escaping (PaySession.TransactionStatus) -> Void) {
        print("Authorised payemnt")
        APIClient.shared.pay(for: checkout, with: authorization) { success, error in
            completeTransaction(success ? .success : .failure)
        }
    }

    func paySessionDidFinish(_ paySession: PaySession) {
        print("Did finish!")
    }

}

However none of the delegate methods are being called when interacting with the Apple Pay sheet which loads as expected in the app. Strangely though, the cancel button the Apple Pay sheet doesn't seem to be working either - which makes me think there is a problem with the PKPaymentAuthorizationControllerDelegate methods in the Mobile Buy SDK.

I tried digging deeper with some break points to see what was going on. I can confirm that the PaySessionDelegate points towards the BasketViewController. I also set breakpoints in the PKPaymentAuthorizationControllerDelegate definitions in PaySession.swift and none of those methods were being called either so it seems there is a problem there hence why none of the PaySessionDelegate` methods are being called.

I have been trying this on iOS 12 on device and on the simulator using 3.3 of the Mobile Buy SDK.

dbart01 commented 5 years ago

The problem is that you're not holding onto the paySession reference that you're creating (in your first snippet). The PaySession object manages all interactions with the PassKit so if you don't keep it alive for the duration of the interaction, none of the callbacks will be handled. It also sounds like your BasketViewController should be the owner of PaySession.

joshgare commented 5 years ago

Thanks for the clarification, retaining the PaySession has fixed this!