After lots of switching packages, configuring gradles, installing pods to make it work. I am finally happy to see google putting an end to this battle with the introduction of pay library. As the name is, its really simple and straight forward, yet I felt there must be some resource out on the internet to help devs to implement such a feature in short time so that you can focus on developing something really awesome.
I am making it very simple where you can just copy paste bunch of lines below and make it work.
First off all you need the following
- Stripe account and publishable key
- Enable apple pay on stripe and upload certificate generated from here
- Google merchant account from here
Now lets start,
Configuration
Apple Pay
And the following json file as your assets file inside /assets/apple_pay.json
folder
{
"provider": "apple_pay",
"data": {
"merchantIdentifier": "<Merchant ID from developer.apple.com>",
"displayName": "<Display Name>",
"merchantCapabilities": [
"3DS",
"debit",
"credit"
],
"supportedNetworks": [
"amex",
"visa",
"discover",
"masterCard"
],
"countryCode": "FR", // Country code
"currencyCode": "EUR", // Currency code
"requiredBillingContactFields": null,
"requiredShippingContactFields": null
}
}
Google Pay
And the following json file as your assets file inside /assets/google_pay.json
folder
{
"provider": "google_pay",
"data": {
"environment": "TEST",
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "stripe",
"stripe:version": "2020-08-27",
"stripe:publishableKey": "<stripe publishable key, eg pk_.......>"
}
},
"parameters": {
"allowedCardNetworks": [
"VISA",
"MASTERCARD"
],
"allowedAuthMethods": [
"PAN_ONLY",
"CRYPTOGRAM_3DS"
],
"billingAddressRequired": false
}
}
],
"merchantInfo": {
"merchantId": "<Merchant ID from pay.google.com/business>",
"merchantName": "<Display Name>"
},
"transactionInfo": {
"countryCode": "FR",
"currencyCode": "EUR"
}
}
}
Flutter Code
Install Package
Inside your pubspec.yaml
file add
pay: 1.0.3 # Latest one at the time of writing
Initialize the package
Somewhere on your code base first enable the package with the above json files from assets that you just added.
Pay _pay = Pay.withAssets(["google_pay.json","apple_pay.json"]);
Check the availability
Once you enable the package, now you can check the availability of the payment service. I link to maintain an array of providers that are available, to do so.
List<PayProvider> availableProviders = [];
PayProvider.values.forEach((e) async {
bool canPay = await _pay.userCanPay(e);
if (canPay) availableProviders.add(e);
});
Show Apple Pay buttons
Option 1 (The quickest) (Either this one or the other one, I prefer the 2nd one)
You can use provided native pay button that can directly process payments by writing everything on the widget to start making the payment happen.
- Google Pay Button
if(availableProviders.contains(PayProvider.google_pay))
GooglePayButton(
paymentConfigurationAsset: "google_pay.json",
onPaymentResult: (Map data){
print(data);
},
paymentItems: [ // You can have multiple items on your payment
PaymentItem(
amount: "100", // Your amount
label: "AwesomeProduct", // Your amount title
status: pay.PaymentItemStatus.final_price, // Status of the payment
type: pay.PaymentItemType.total, // Type of the payment
)
],
)
- Apple Pay Button
if(availableProviders.contains(PayProvider.apple_pay))
ApplePayButton(
paymentConfigurationAsset: "apple_pay.json",
onPaymentResult: (Map data){
print(data);
},
paymentItems: [ // You can have multiple items on your payment
PaymentItem(
amount: "100", // Your amount
label: "AwesomeProduct", // Your amount title
status: pay.PaymentItemStatus.final_price, // Status of the payment
type: pay.PaymentItemType.total, // Type of the payment
)
],
)
Option 2 (The best, IMO)
If you want to separate business code and the UI code, this is the one for you. Instead of using the provided widget you can use any widget (Make sure you comply with button guidlies from Apple Pay or Google Pay)
Map<String, dynamic> data = await _pay.showPaymentSelector(
provider: provider // Can be supported provider (PayProvider.apple_pay, PayProvider.google_pay),
paymentItems: [
PaymentItem(
label: "Awesome Product",
amount: "100",
type: PaymentItemType.item,
status: PaymentItemStatus.final_price,
),
],
);
After any of the option, you will get a response with a Map data
. The reason it's a Map and not a typed value is every provider returns response on their own pattern so to support multiple providers, pay packages is making to map to make the package as raw as possible.
From the response, all you need is token which should be as follows
String tokenToBeSentToCloud = data["token"];
Server Side
Making actual charge to the user's card
After you have a token, you now need to have a backend code(can also be on on flutter, not recommended) to process the payment. I am using a node.js server to process the payment using the token from mobile.
Install the package
npm install stripe
or yarn add stripe
Initialize the package
export const stripe = new Stripe("<stripe_secret_key>", {
apiVersion: "2020-08-27"
});
Make a charge
const paymentMethod = await stripe.paymentMethods.create({
type: "card",
card: {
token: "<token from pay package>"
}
})
await stripe.paymentIntents.create({
amount: 10000, // Amount in cents, can be different from what you presented on the pay dialog on mobiel
currency: "EUR", // Currentcy
capture_method: "automatic", //
customer: "<Optional, if you have customer on stripe>",
payment_method: paymentMethod.id,
receipt_email: "<If you want to send reciept in email>,
statement_descriptor: "<Statement Label(max 22 chars)>",
confirm: true, // True charges the card instantly
description: "Product description"
})
Voila, you just charges a user.
Now there are other cool things that you can do with stripe.js SDK, for that checkout stripe documentation for more features.
Top comments (2)
the token is giving a string that is a JSON that has a data, yet when I send it it gives invalid error
Also facing the same issue with the Apple Pay token, for google pay token it is working fine. Do let me know if you find any solution on this.