NativeScript / plugins

@nativescript plugins to help with your developments.
https://docs.nativescript.org/plugins/index.html
Apache License 2.0
190 stars 108 forks source link

Apple Pay plugin: "The data couldn't‚ [...] isn't in the correct format." #125

Open KATT opened 3 years ago

KATT commented 3 years ago

Environment:

Setup

Registering the button in my main.js like this:

import { ApplePayBtn } from '@nativescript/apple-pay';
Vue.registerElement('ApplePayBtn', () => ApplePayBtn, {});

In component

Using the button like this:

<ApplePayBtn @tap="buy" buttonType="Buy" />

When clicking the button, here's my buy code (commented some stuff out as we haven't reached that point yet)

methods.buy:


async buy(args) {
    console.log('buy', args.object)

    const applePayBtn = args.object // as ApplePayBtn;
    applePayBtn.once(ApplePayEvents.DidAuthorizePaymentHandler, async (args /*: AuthorizePaymentEventData*/) => {
        // ❌ We never get here as the app crashes before
        console.log('DidAuthorizePaymentHandler', 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
            }
        };

    });

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

    const request = {
        paymentItems,
        merchantId: appleMerchantID, // the merchant ID for this app
        merchantCapabilities: ApplePayMerchantCapability.ThreeDS,
        countryCode: 'US',
        currencyCode: 'USD',
        shippingContactFields: [],
        billingContactFields: [],
        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);
    });

After clicking the button createPaymentRequest() seem to create it all right because the Apple Pay stuff comes up but after selecting payment method

Full 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:/tappy/node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js:42: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:/tappy/node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js:42:0)
', reason: '(null)'
*** First throw call stack:
(
0   CoreFoundation                      0x0000000114497fba __exceptionPreprocess + 242
1   libobjc.A.dylib                     0x0000000114341ff5 objc_exception_throw + 48
2   NativeScript                        0x000000010cd28914 _ZN3tns21NativeScriptException15OnUncaughtErrorEN2v85LocalINS1_7MessageEEENS2_INS1_5ValueEEE + 914
3   NativeScript                        0x000000010d188f65 _ZN2v88internal14MessageHandler25ReportMessageNoExceptionsEPNS0_7IsolateEPKNS0_15MessageLocationENS0_6HandleINS0_6ObjectEEENS_5LocalINS_5ValueEEE + 341
4   NativeScript                        0x000000010d188dd4 _ZN2v88internal14MessageHandler1
KATT commented 3 years ago

Also planning to hook this up to Stripe as the next step - has anyone done this? - I imagine I just pass that something of that object to a backend function that talks to Stripe.

asharghi commented 3 years ago

I'm currently using this one for Stripe: https://github.com/triniwiz/nativescript-plugins/tree/master/packages/nativescript-stripe

But would be nice to have one single plugin for payment

KATT commented 3 years ago

I've been trying to integrate that but running into problems with 3dsecure and right now we just need a "Pay with Apple Pay"-button anyway. (if you have a couple hours this week and want to do get freelance $, let me know, my contact details is in my bio)

NathanWalker commented 3 years ago

@KATT when you get a chance could you try something? Open this file:

code node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js

On line 42, change it to this:

var pData = NSJSONSerialization.JSONObjectWithDataOptionsError(payment.token.paymentData, NSJSONReadingOptions.MutableContainers);

Save that and try in your app directly to see if any better. If you still see issue, that error is usually related to an unfinished json string (still receiving the full json data) - see here for few more suggestions you could try - if you find one the fixes your case we can add some extra condition handling in there: https://stackoverflow.com/questions/37825284/the-data-couldn-t-be-read-because-it-isn-t-in-the-correct-format

KATT commented 3 years ago

@NathanWalker no visible change on that unfortunately - crashes as well.

``` ***** 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:/tappy/node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js:42: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:/tappy/node_modules/@nativescript/apple-pay/payment-authorization-view-controller-delegate.ios.js:42:0) ', reason: '(null)' *** First throw call stack: ( 0 CoreFoundation 0x0000000112a65fba __exceptionPreprocess + 242 1 libobjc.A.dylib 0x000000011290fff5 objc_exception_throw + 48 2 NativeScript 0x000000010b2f6914 _ZN3tns21NativeScriptException15OnUncaughtErrorEN2v85LocalINS1_7MessageEEENS2_INS1_5ValueEEE + 914 3 NativeScript 0x000000010b756f65 _ZN2v88internal14MessageHandler25ReportMessageNoExceptionsEPNS0_7IsolateEPKNS0_15MessageLocationENS0_6HandleINS0_6ObjectEEENS_5LocalINS_5ValueEEE + 341 4 NativeScript 0x000000010b756dd4 _ZN2v88internal14MessageHandler1 ```
bradmartin commented 3 years ago

@KATT - did you solve this? As for integrating with Stripe, if that is your approach, Stripe would be your payment processor with this workflow, this plugin provides the Apple Pay button (official API from Apple) and Apple handles the confirmation of the transaction with the user info on the device. Outside of that, is where you'd need your payment processor (Stripe, FirstData, etc.) to handle the actual payment/charge of the card.

Do you have your merchant ID for apple pay setup? The README links to the steps Apple forces you to do in order to use the Apple Pay APIs. Without following those steps, it is possible the error/crash is happening because your Apple Dev account isn't setup correctly.

mahmoudajawad commented 3 years ago

@NathanWalker, @bradmartin , I'm hitting the same issue now. I applied the change you suggested but still getting the error. Btw, I'm on simulator, is that an issue? Also, I added log messages in the file you referred to, and the error is definitely happening at line 42.

UPDATE: To answer Brad earlier question to OP, yes I made sure the merchant ID is updated in xcode and reflecting correctly, as well as using the same id in the code snippet.

KATT commented 3 years ago

We stopped using NativeScript altogether after we got the MVP in place - we used this third party plugin.

I've unsubscribed from this issue - feel free to close it.

bradmartin commented 3 years ago

@NathanWalker, @bradmartin , I'm hitting the same issue now. I applied the change you suggested but still getting the error. Btw, I'm on simulator, is that an issue? Also, I added log messages in the file you referred to, and the error is definitely happening at line 42.

UPDATE: To answer Brad earlier question to OP, yes I made sure the merchant ID is updated in xcode and reflecting correctly, as well as using the same id in the code snippet.

It has been a couple months since I worked on this but from Apple docs:

Note

Not all Apple Pay features are supported in the iOS simulator. Testing Apple Pay is unsupported in the watchOS simulator.
mahmoudajawad commented 3 years ago

@bradmartin, thank for your reply. I'll spare sometime for testing on an iphone later, but wanted to hear from you first. I'll have a look and revert back here with what I find.

bradmartin commented 3 years ago

I know the plugin should be working fine, one of the pain points i had in developing this was the encryption of the data to the payment provider. Testing this with all the various providers isn't something that can be done simply so I only know 100% that Payeezy/FirstData works 100% with this plugin. So it's possible other providers might have different encryption needs on the data.