NativeScript / payments

In-App Purchase, Subscriptions, Google Pay, Apple Pay for NativeScript
Apache License 2.0
34 stars 10 forks source link

App crash when using apple pay #25

Open abdallahkadour opened 1 year ago

abdallahkadour commented 1 year ago

Error:

***** Fatal JavaScript exception - application has been terminated. *****
NativeScript encountered a fatal error: Uncaught Error: The data couldn’t be read because it isn’t in the correct format.
at
PKPaymentAuthorizationViewControllerDelegateImpl.paymentAuthorizationViewControllerDidAuthorizePaymentHandler(file: src/webpack:/vois-mgov/node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js:43:0)
(CoreFoundation) *** Terminating app due to uncaught exception 'NativeScript encountered a fatal error: Uncaught Error: The data couldn’t be read because it isn’t in the correct format.
at
PKPaymentAuthorizationViewControllerDelegateImpl.paymentAuthorizationViewControllerDidAuthorizePaymentHandler(file: src/webpack:/vois-mgov/node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js:43:0)
', reason: '(null)'
*** First throw call stack:
(
0   CoreFoundation                      0x00007fff20406d44 __exceptionPreprocess + 242
1   libobjc.A.dylib                     0x00007fff201a4a65 objc_exception_throw + 48
2   NativeScript                        0x000000010610de7e __copy_helper_block_e8_32o + 0
3   libdispatch.dylib                   0x00007fff201148e4 _dispatch_call_block_and_release + 12
4   libdispatch.dylib                   0x00007fff20115b25 _dispatch_client_callout + 8
5   libdispatch.dylib                   0x00007fff20123043 _dispatch_main_queue_drain + 1050
6   libdispatch.dylib                   0x00007fff20122c1b _dispatch_main_queue_callback_4

code:

const MERCHANTID = '388333172821828292929';
const SomeIdentifierFromPaymentProvider = '89290109290129912088';

export const onApplePayTap = async (args?: any) => {
  //try {
  // just ensuring this runs only on iOS
  if (isIOS) {
    const applePayBtn = args.object as ApplePayBtn

    // setup the event listeners for the delegate for apple pay for our button
    applePayBtn.once(ApplePayEvents.DidAuthorizePaymentHandler, async (args: any) => {
      console.log('in authorize handler')
      console.log(ApplePayEvents.DidAuthorizePaymentHandler)

      // this is where you do backend processing with your payment provider (Stripe, PayPal, etc.)
      // this payload is just a sample, your payload to a provider will likely be different
      // you can see here how to access the encrypted values from Apple Pay inside the `args.data.paymentData`
      const payloadToBackend = {
        transaction_type: 'purchase',
        merchant_ref: args.data.paymentData.header.transactionId,
        method: '3DS',
        '3DS': {
          merchantIdentifier: SomeIdentifierFromPaymentProvider,
          data: args.data.paymentData.data,
          signature: args.data.paymentData.signature,
          version: args.data.paymentData.version,
          header: args.data.paymentData.header
        }
      }

      const result = true //await this.someHttpMethodToYourProviderBackend(payloadToBackend)

      if (result) {
        // need this to call when the payment is successful to close the payment sheet correctly on iOS
        args.completion(ApplePayTransactionStatus.Success)
        // now you can follow through with your user flow since the transaction has been successful with your provider
      } else {
        // payment failed on the backend, so show the FAILURE to close the Apple Pay sheet
        args.completion(ApplePayTransactionStatus.Failure)
      }
    })

    // these are the items your customer is paying for
    const paymentItems = ([
      {
        amount: 20.5,
        label: 'Balance',
        type: ApplePayPaymentItemType.Final
      }
    ] as unknown) as ApplePayItems[]

    const request = {
      paymentItems,
      merchantId: MERCHANTID // the merchant ID for this app
      merchantCapabilities: ApplePayMerchantCapability.ThreeDS,
      countryCode: 'US',
      currencyCode: 'USD',
      shippingContactFields: [ApplePayContactFields.Name, ApplePayContactFields.PostalAddress],
      billingContactFields: [ApplePayContactFields.Name, ApplePayContactFields.PostalAddress],
      supportedNetworks: [
        ApplePayNetworks.Amex,
        ApplePayNetworks.Visa,
        ApplePayNetworks.Discover,
        ApplePayNetworks.MasterCard
      ]
    } as ApplePayRequest

    // `createPaymentRequest` will call into the Apple Pay SDK and present the user with the payment sheet for the configuration provided
    await applePayBtn.createPaymentRequest(request).catch((err) => {
      console.log('Apple Pay Error', err)
    })
  }
abdallahkadour commented 1 year ago

The reason that payment in the following function is an empty object:

 /**
     * Tells the delegate that the user has authorized the payment request and asks for a result.
     * @param controller
     * @param payment
     * @param completion
     */
    PKPaymentAuthorizationViewControllerDelegateImpl.prototype.paymentAuthorizationViewControllerDidAuthorizePaymentHandler = function (controller, payment, completion) {

The function is defined the file payment-authorization-view-controller-delegate.ios.js

Any idea?

kakha13 commented 10 months ago

You need to use real device with Sandbox test account and everything works great