DEV Community

Cover image for Google Pay and Apple pay using Stripe on Flutter
Avaaj Gyawali
Avaaj Gyawali

Posted on

Google Pay and Apple pay using Stripe on Flutter

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Flutter Code

Install Package

Inside your pubspec.yaml file add

pay: 1.0.3 # Latest one at the time of writing
Enter fullscreen mode Exit fullscreen mode

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"]);
Enter fullscreen mode Exit fullscreen mode

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);
    });
Enter fullscreen mode Exit fullscreen mode

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.

  1. 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
        )
      ],
    )
Enter fullscreen mode Exit fullscreen mode
  1. 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
        )
      ],
    )
Enter fullscreen mode Exit fullscreen mode

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,
        ),
      ],
    );
Enter fullscreen mode Exit fullscreen mode

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"];
Enter fullscreen mode Exit fullscreen mode

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"
});
Enter fullscreen mode Exit fullscreen mode

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"
    })
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
nimr77 profile image
Nimr

the token is giving a string that is a JSON that has a data, yet when I send it it gives invalid error

Collapse
 
mpokar profile image
Mitesh pokar

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.