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

Configuration

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"
    }
  }
}

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
  }
}

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.

  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
        )
      ],
    )
  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
        )
      ],
    )

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"
    })

Here is, you just charges a user.

Comments are closed.