Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(): add method payWithGooglePay and payWithApplePay #90

Closed
metalllus opened this issue Aug 1, 2021 · 64 comments
Closed

feat(): add method payWithGooglePay and payWithApplePay #90

metalllus opened this issue Aug 1, 2021 · 64 comments
Labels
enhancement New feature or request

Comments

@metalllus
Copy link

Hi, ok, so this is the thing. I have an Angular Firebase PWA with implemented payments thru Stripe.js (Stripe Elements). When I upgraded my project to Ionic 5 Capacitor, my implementation works (card payments work fine) except for Apple Pay and Google Pay. My question is if it is possible to use your plugin solely to make the Google Pay/Apple Pay payment on native device after the user selects payment with Apple Pay/Google Pay in my UI. I do not need the payment sheet I just need to invoke the Google Pay/Apple Pay on the native device. The web implementation of Stripe.js cannot do this on native device, it works only on the web.

@rdlabo
Copy link
Member

rdlabo commented Aug 2, 2021

@metalllus payWithGooglePay/payWithApplePay is removed in v3, but reason is not unnecessary. It's because everything was remade and refactored.

Will implements. But I won't have time to implement it right away, but welcome to create a pull request.

@rdlabo
Copy link
Member

rdlabo commented Aug 2, 2021

If you can, please tell me why it is not convenient to have a PaymentSheet.

@rdlabo rdlabo changed the title payWithGooglePay/payWithApplePay no longer available? feat(): add method payWithGooglePay and payWithApplePay Aug 2, 2021
@metalllus
Copy link
Author

metalllus commented Aug 3, 2021

If you can, please tell me why it is not convenient to have a PaymentSheet.

For me, it is a question of UI design and functionality. When I coded my PWA I made a custom implementation of the payment interface thru Stripe Elements to fit my site both design-wise and functionality-wise. When I upgraded the PWA to Ionic hybrid app I found out that everything I had prepared works fine, the only thing that does not work is invoking the GooglePay/Apple Pay interface on mobile to get the paymentMethod to use in Stripe.js confirmCardPayment() method to finish the payment. This cannot be done via the PaymentRequest in Stripe.js, on mobile it simply does not work. Hence it would be totally awesome to have the possibility to do just these things:

  1. provide a method to check if GooglePay/Apple Pay is available on client device (check if device is compatible and at least one card is added to the digital wallet) - this would be needed to decide if Apple Pay/Google Pay option would be shown to the user
  2. provide a method to make a call to display the GooglePay/Apple Pay mobile interface with the amount of my choice
  3. the method should return the paymentMethod from the Google Pay/Apple Pay interface if the user makes the payment
  4. close the GooglePay/Apple Pay interface; I would then use the acquired paymentMethod to finish the payment with the Stripe.js confirmCardPayment() method.

This way all the people who have their custom implementation up and running with Stripe.js would need to change only a few lines of code to make their Google Pay/Apple Pay working on mobile and could continue using their web implementation because as I said everything else works fine on Ionic, no need to use the payment sheet.

@rdlabo rdlabo added the enhancement New feature or request label Aug 3, 2021
@DanProudfoot
Copy link

Hi - I haven't looked too deeply into this plugin, but what @metalllus says seems to absolutely hit the nail on the head - I want to be able design my own flow, and when the time comes the Apple or Google pay native UI is called from this Capacitor plugin, which then lets me do with the payment information what I wish.

@Phoenix-Alpha
Copy link

@metalllus, not sure how you use stripe.js in mobile project. It will be working on web but won't work in mobile apps. Could you let me know how?

@metalllus
Copy link
Author

@Phoenix-Alpha I use it the same way as on the web, no changes whatsover. After all, when porting my app from a web Angular PWA to Ionic native, the only features one needs to change are the ones using native device features, i. e. geolocation, camera, etc. In case of Stripe, the only part that relies on native device features is the call to Apple Pay/Google Pay. Everything else can be done with the Stripe.js web library. Tested with iPhone and Android simulators. Therefore the only thing I need from this plugin is to call the Apple Pay/Google Pay native interface to get the payment method to be used afterwards to confirm the Apple Pay/Google Pay payment.

@Phoenix-Alpha
Copy link

@metalllus, thanks for your explanation. AFAIK, stripe.js is only working on websites hosted on https in live mode. It works on non-https though in test mode. Not sure your app is working fine in live mode?

@metalllus
Copy link
Author

@Phoenix-Alpha You are absolutely right my friend, my bad. I did not take into account the https requirement in live mode and did not test for that, unfortunately :( Thanks a million for setting me straight.

@madmacc
Copy link

madmacc commented Aug 24, 2021

I just upgraded to v1.1.0 of @capacitor-community/stripe to see if apple pay works. I guess not. Looks great though otherwise.

I have the same issue with my Ionic app in that I need to support Apple pay to be allowed to accept donations in the app store.
All other payment functions are working fine using Stripe.js.

I had this working with the previous version of @capacitor-community/stripe but it required a merchantId whereas Apple Pay on Stripe.js does not require a merchantId.

Unfortunately the only way to use Apple pay on Stripe.js is outside of the Ionic app then via a success url to a webpage and finally back to the app with a deeplink. Not a great user experience and not sure if it would pass the app review process.

So I am still looking for solutions.
Any near term plans to add apple and google pay?

@rdlabo
Copy link
Member

rdlabo commented Aug 28, 2021

@rdlabo
Copy link
Member

rdlabo commented Aug 28, 2021

GooglePay's reference: https://stripe.com/docs/google-pay

@rdlabo
Copy link
Member

rdlabo commented Aug 28, 2021

@madmacc

Any near term plans to add apple and google pay?

Apple Pay is supported with v3.1.0. We will support Google Pay, too. I will work when I have time, but I won't have time to implement it right away. Welcome create a pull request.

@metalllus
Copy link
Author

metalllus commented Aug 28, 2021

Just a reminder for everybody viewing this thread - I was wrong and javascript SDK WILL NOT work in ionic native environment. It is quite deceiving becausing everything works fine in development mode but once you switch to production, the stripe javascript sdk starts demanding HTTPS and you are done. There is no way to get around it in ionic native environment, as far I know. Therefore I had to switch to the payment sheet provided by this plugin as I could not find any other way to make payments work on native.

@madmacc
Copy link

madmacc commented Aug 28, 2021

@rdlabo Awesome that's great thanks for the hard work. I'll give Apple Pay a try this week. Google pay is not such a priority for me.

@metalllus Yes but that is just for Apple pay as it requires https://.
A webview (Ionic) or iFrame and is blocked by Stripe as it requires the request urlScheme to be https:// and Ionic uses a local urlScheme of capacitor:// not https://
All other Stripe.js functionality works fine from Ionic.

I actually submitted a request to Stripe to allow capacitor:// and they said it is in the list to be reviewed but I doubt they will implement it.

@metalllus
Copy link
Author

@madmacc you mean that standard card payments implemented via the javascript SDK work for you in production mode on native devices (iOS and Android) in Ionic/Capacitor? In my solution I implemented card payments with Stripe Elements to generate fields for the user to enter card information, in dev mode everything works fine including the payment itself but in production mode, the Stripe Elements card fields do not even get displayed.

@madmacc
Copy link

madmacc commented Aug 28, 2021

@metalllus Yes they work fine. I use various Stripe Elements and other various calls to get products, payment methods etc. I have this in a production mobile app and it has worked for around 5000 users.

To clarify what do you mean by production mode vs dev mode?
I am using an Ionic prod build and using a live stripe account.

@DanProudfoot
Copy link

@madmacc I've found the same thing. I naively switched my app over to a device-hosted capacitor build (previously we were showing an online webpage, basically) and Stripe has continued to work, including showing elements. We still get the warning about live mode over http but creating a new setupIntent has continued to work, so 🤷 I have no idea what the real limitations are.

@madmacc
Copy link

madmacc commented Aug 28, 2021

@DanProudfoot The only limitation I have found so far has been Apple Pay.
The only solutions I have found for Apple pay are to use this Capacitor plugin or to redirect the user externally to a web page to use apple pay and then on completion use a deep link via a web page to take them back to the app.

@metalllus
Copy link
Author

metalllus commented Aug 29, 2021

@rdlabo hi, two questions/observations:

  1. how is the isApplePayAvailable() method supposed to work? I would expect the promise to return a boolean but as per the docs the promise returns void so I am not sure how to use it properly. I am testing on a real iPhone, I initialize stripe with Stripe.initialize(publishableKey: ...) and then use the Stripe.isApplePayAvailable() method, but the promise doesn't seem to fire or return anything.
  2. Regarding the ApplePay payment flow itself, on iPhone simulator everything works as expected but on a real device, in my case iPhone 7, when I await Stripe.createApplePay() method and then I use the Stripe.presentApplePay(), even though the Apple Pay interface does not appear on screen, the ApplePayEventsEnum.Completed listener fires (the behavior is the same in stripe live and test mode on iPhone 7) and nothing more happens.

@madmacc today I dug deeper and yes, the card payments do indeed work on native platforms via the javascript SDK, I managed to make a real payment on the iPhone emulator.

@rdlabo
Copy link
Member

rdlabo commented Aug 30, 2021

@metalllus

how is the isApplePayAvailable() method

I forgot implement isApplePayAvailable method. I fixed https://github.com/capacitor-community/stripe/releases/tag/v3.1.1

the ApplePayEventsEnum.Completed listener fires

Sorry, this is my mistake: 2f02b9c

This event is Canceled(fixed v3.1.2). Stripe may returned userCancellation. Is there an error in the log of Xcode? ??

@madmacc
Copy link

madmacc commented Aug 30, 2021

@rdlabo I tested this on an iPhone emulator and a real ios device. It appears to work on the emulator although I did not put the payment through.
On the real device I get the error below on Stripe.presentApplePay and it does not display it.

I am using development Stripe Mode not live.

ERROR MESSAGE:  {"errorMessage":"STPApplePayContext is failed","message":"STPApplePayContext is failed"}
⚡️  [error] - {"errorMessage":"STPApplePayContext is failed","message":"STPApplePayContext is failed"}
⚡️  [error] - ERROR {"rejection":{"errorMessage":"STPApplePayContext is failed"},"promise":{"__zone_symbol__state":0,"__zone_symbol__value":"..."},"zone":{"_parent":{"_parent":null,"_name":"<root>","_properties":{},"_zoneDelegate":{"_taskCounts":{"microTask":0,"macroTask":0,"eventTask":0},"zone":"...","_parentDelegate":null,"_forkZS":null,"_forkDlgt":null,"_forkCurrZone":null,"_interceptZS":null,"_interceptDlgt":null,"_interceptCurrZone":null,"_invokeZS":null,"_invokeDlgt":null,"_invokeCurrZone":null,"_handleErrorZS":null,"_handleErrorDlgt":null,"_handleErrorCurrZone":null,"_scheduleTaskZS":null,"_scheduleTaskDlgt":null,"_scheduleTaskCurrZone":null,"_invokeTaskZS":null,"_invokeTaskDlgt":null,"_invokeTaskCurrZone":null,"_cancelTaskZS":null,"_cancelTaskDlgt":null,"_cancelTaskCurrZone":null,"_hasTaskZS":null,"_hasTaskDlgt":null,"_hasTaskDlgtOwner":null,"_hasTaskCurrZone":null}},"_name":"angular","_properties":{"isAngularZone":true},"_zoneDelegate":{"_taskCounts":{"microTask":0,"macroTask":0,"eventTask":13},"zone":"...","_parentDelegate":"...","_forkZS":null,"_forkDlgt":null,"_forkCurrZone":null,"_interceptZS":null,"_interceptDlgt":null,"_interceptCurrZone":null,"_invokeZS":{"name":"angular","properties":"..."},"_invokeDlgt":"...","_invokeCurrZone":"...","_handleErrorZS":"...","_handleErrorDlgt":"...","_handleErrorCurrZone":"...","_scheduleTaskZS":{"name":""},"_scheduleTaskDlgt":"...","_scheduleTaskCurrZone":"...","_invokeTaskZS":"...","_invokeTaskDlgt":"...","_invokeTaskCurrZone":"...","_cancelTaskZS":"...","_cancelTaskDlgt":"...","_cancelTaskCurrZone":"...","_hasTaskZS":"...","_hasTaskDlgt":"...","_hasTaskDlgtOwner":"...","_hasTaskCurrZone":"..."}},"task":{"type":"microTask","state":"notScheduled","source":"Promise.then","zone":"angular","runCount":0}}

@metalllus
Copy link
Author

@rdlabo I tested this on an iPhone emulator and a real ios device. It appears to work on the emulator although I did not put the payment through.
On the real device I get the error below on Stripe.presentApplePay and it does not display it.

I am using development Stripe Mode not live.

ERROR MESSAGE:  {"errorMessage":"STPApplePayContext is failed","message":"STPApplePayContext is failed"}
⚡️  [error] - {"errorMessage":"STPApplePayContext is failed","message":"STPApplePayContext is failed"}
⚡️  [error] - ERROR {"rejection":{"errorMessage":"STPApplePayContext is failed"},"promise":{"__zone_symbol__state":0,"__zone_symbol__value":"..."},"zone":{"_parent":{"_parent":null,"_name":"<root>","_properties":{},"_zoneDelegate":{"_taskCounts":{"microTask":0,"macroTask":0,"eventTask":0},"zone":"...","_parentDelegate":null,"_forkZS":null,"_forkDlgt":null,"_forkCurrZone":null,"_interceptZS":null,"_interceptDlgt":null,"_interceptCurrZone":null,"_invokeZS":null,"_invokeDlgt":null,"_invokeCurrZone":null,"_handleErrorZS":null,"_handleErrorDlgt":null,"_handleErrorCurrZone":null,"_scheduleTaskZS":null,"_scheduleTaskDlgt":null,"_scheduleTaskCurrZone":null,"_invokeTaskZS":null,"_invokeTaskDlgt":null,"_invokeTaskCurrZone":null,"_cancelTaskZS":null,"_cancelTaskDlgt":null,"_cancelTaskCurrZone":null,"_hasTaskZS":null,"_hasTaskDlgt":null,"_hasTaskDlgtOwner":null,"_hasTaskCurrZone":null}},"_name":"angular","_properties":{"isAngularZone":true},"_zoneDelegate":{"_taskCounts":{"microTask":0,"macroTask":0,"eventTask":13},"zone":"...","_parentDelegate":"...","_forkZS":null,"_forkDlgt":null,"_forkCurrZone":null,"_interceptZS":null,"_interceptDlgt":null,"_interceptCurrZone":null,"_invokeZS":{"name":"angular","properties":"..."},"_invokeDlgt":"...","_invokeCurrZone":"...","_handleErrorZS":"...","_handleErrorDlgt":"...","_handleErrorCurrZone":"...","_scheduleTaskZS":{"name":""},"_scheduleTaskDlgt":"...","_scheduleTaskCurrZone":"...","_invokeTaskZS":"...","_invokeTaskDlgt":"...","_invokeTaskCurrZone":"...","_cancelTaskZS":"...","_cancelTaskDlgt":"...","_cancelTaskCurrZone":"...","_hasTaskZS":"...","_hasTaskDlgt":"...","_hasTaskDlgtOwner":"...","_hasTaskCurrZone":"..."}},"task":{"type":"microTask","state":"notScheduled","source":"Promise.then","zone":"angular","runCount":0}}

In my case, on the emulator everything works fine and the payment goes through no problem. On real device though I have exactly the same issue as @madmacc.

@metalllus
Copy link
Author

@rdlabo @madmacc Ok guys, I am sorry. The problem was caused by my mistake. I did not know the mechantDisplayName in the createApplePay() method should actually hold the merchantIdentifier. The property name is not ideal, it is quite confusing because I think the displayName is something else. But once I entered the merchant ID, everything works.

@rdlabo
Copy link
Member

rdlabo commented Aug 30, 2021

@metalllus Yes, great!! Thanks your confirm. And this is right, label of merchantDisplayName is wrong. I will fix this. Thanks.

@rdlabo
Copy link
Member

rdlabo commented Aug 30, 2021

Changed label: d6b78f4

@metalllus
Copy link
Author

@rdlabo suggestion: wouldn't it be better if the isApplePayAvailable() method resolved with true if applePay is available and with false if it is not available? Then it would be cleaner to use with async/await syntax to avoid having to use .then().

@rdlabo
Copy link
Member

rdlabo commented Sep 5, 2021

@metalllus Thanks for testing.

Did you run initialize first??

Stripe.initialize({
  publishableKey: "Your Publishable Key""",
});

And I did some update now(I don't know if it resolve error). Please try v3.2.0-4 . Thanks.

@metalllus
Copy link
Author

@rdlabo I did initialize, yes. First I initialize, then check if google pay is available and if yes, only then I display GooglePay button. It all functions great on the emulator, the payment succeeds. This time on your new version v3.2.0-4, the payment succeeds and the completed listener never fires so the app does not crash. The cancel button still crashes the app.

When I run the same code on a real device I get the error I sent you during build in Android Studio, the app does not compile at all. No change in v3.2.0-4.

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus

the app does not compile at all. No change in v3.2.0-4.

I understood. for Google Pay, we may need initialize in plugin load. I will work.

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus released v3.2.0-5. This version require new variables:

<string name="publishable_key">Your Publishable Key</string>
<bool name="enable_google_pay">true</bool>
<meta-data
  android:name="com.getcapacitor.community.stripe.publishable_key"
  android:value="@string/publishable_key"/>

<meta-data
  android:name="com.getcapacitor.community.stripe.enable_google_pay"
  android:value="@bool/enable_google_pay"/>

How about work?? (This development may difficult without Andoid real devices ...)

@metalllus
Copy link
Author

metalllus commented Sep 6, 2021

@rdlabo Ok, we are making progress, now we have exactly the same behavior on the emulator and on real device. The app compiles, the payment is successful. The only problem we have is that the listeners do not fire at all. Everything else seems to work fine. I have experienced no app crashes. If you manage to fix the listeners I think we are done.

To add the listeners, I use

Stripe.addListener(GooglePayEventsEnum.Completed, () => {
        ...
      });

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus Really?! Thanks for awesome news!! I was wondering if I would buy a real Android device for this_φ(・_・

listeners is fixed v3.2.0-6. This reason is my typo... Please test. Thanks.

@metalllus
Copy link
Author

metalllus commented Sep 6, 2021

@rdlabo Everything works, great. Tested in emulator and on real device. However, all this was tested ONLY with the stripe test environment. If I want to pay with stripe live account, do I have to do this?

2021-09-06_12-00-02

With live payments the google-pay-is-testing in strings.xml should be false?
<bool name="google_pay_is_testing">false</bool>

And one final thing, in your docs these to sentences should be exchanged.
2021-09-06_12-04-45

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus

If I want to pay with stripe live account, do I have to do this?

Yes. With <bool name="google_pay_is_testing">false</bool> is changed GooglePayEnvironment.Test or GooglePayEnvironment.Production. When you passed process of 5, please change to true.

Oh, yes. I will change. Thanks!

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus Can you give screenshot of Google Pay for readme ?
Like: https://github.com/capacitor-community/stripe/blob/master/demo/screenshots/apple-pay-ios.png

I remembered I can't shot this...

@metalllus
Copy link
Author

@rdlabo I do not know why but the Stripe always displays the interface in Slovak language, even if I set country_code to US in strings.xml, it makes no difference. I wanted to switch to English to make you a screenshot in English but it does not work. Maybe my Stripe account settings override this, I am not sure. Why doesn't it work for you in the emulator? In my case everything works no problem.

2021-09-06_13-48-50

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus Stripe check device language, may not strings.xml. (in iOS is right).
Please try to change device language. thanks.

@metalllus
Copy link
Author

@rdlabo here you go.
2021-09-06_14-30-18

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus Thanks. I updated readme with your image, and released Google Pay method at main release!!

@capacitor-community capacitor-community deleted a comment from allcontributors bot Sep 6, 2021
@metalllus
Copy link
Author

@rdlabo sorry, I've never done this, what exactly should I do? what do you mean by 'specify contributions'?

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus I think you work many test, and giving screenshot to readme. So I want to add Contributors list. But bot require created pull request. mmm...
Think a little about how to do it.

@capacitor-community capacitor-community deleted a comment from allcontributors bot Sep 6, 2021
@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

OK. I could make allcontributors bot create pull request: #99

@metalllus
Copy link
Author

@rdlabo Do you need me to do something or...?

@rdlabo
Copy link
Member

rdlabo commented Sep 6, 2021

@metalllus Not need about allcontributors👍

Now that the work is complete, please close the issue if there is no problem.

@malua
Copy link

malua commented Nov 4, 2021

@metalllus
I just came across this issue and wanted to tell you that stripe js does work with capacitor. you just have to set

server: {
  androidScheme: 'https',
  iosScheme: 'ionic'
}

ionic is whitelisted by the stripe js script and https on android will work anyway.

@metalllus
Copy link
Author

@malua do apple pay/google pay payments work for you through stripe.js as well? You see, normal card payments were never a problem, just apple pay and google pay payments which are solved by this capacitor plugin.

@madmacc
Copy link

madmacc commented Nov 4, 2021

@malua Does that actually work for you with Apple Pay?

I spent quite a bit of time trying to change the urlScheme but it seemed to not be possible.
I saw that ionic was whitelisted in the code.
You can look at the stripe.js code and search for "ionic".

I have seen numerous comments from people saying this is not possible.

@malua
Copy link

malua commented Nov 5, 2021

ah sorry!! i misunderstood the issue... no that won't work.

I saw that ionic was whitelisted in the code.
You can look at the stripe.js code and search for "ionic".

yes thats how i found out as well. and i thought you might not know that, but of course this issue is only related to apple/google pay.

sorry!

@rdlabo
Copy link
Member

rdlabo commented Jan 19, 2022

Did you adapt this plugin for production? If yes, please tell us what app. Please help us to develop this plugin in 2022.
#145
Thanks.

@metalllus
Copy link
Author

metalllus commented Jan 19, 2022 via email

@davidemerritt
Copy link

davidemerritt commented Jun 24, 2022

Changed label: d6b78f4

Just a heads up that the web docs for apple pay still reference merchantDisplayName which threw me off as well.

https://stripe.capacitorjs.jp/docs/apple-pay

@93lucasp
Copy link

93lucasp commented Dec 11, 2023

Changed label: d6b78f4

Just a heads up that the web docs for apple pay still reference merchantDisplayName which threw me off as well.

https://stripe.capacitorjs.jp/docs/apple-pay

yes please update the doc, I spent 2 hours because of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

8 participants