pub package

A plugin to add payments to your Flutter application.

Platform Support

Android iOS
Google Pay Apple Pay

Getting started

Before you start, create an account with the payment providers you are planning to support and follow the setup instructions:

Apple Pay:

  1. Take a look at the integration requirements.
  2. Create a merchant identifier for your business.
  3. Create a payment processing certificate to encrypt payment information.

Google Pay:

  1. Take a look at the integration requirements.
  2. Sign up to the business console and create an account.

Usage

To start using this plugin, add pay as a dependency in your pubspec.yaml file:

dependencies:
  pay: ^3.0.0-beta.2

Define the configuration for your payment provider(s). Take a look at the parameters available in the documentation for Apple Pay and Google Pay, and explore the sample configurations in this package.

Example

This snippet assumes the existence of a payment configuration for Apple Pay (defaultApplePayConfigString) and another one for Google Pay (defaultGooglePayConfigString):

import 'package:pay/pay.dart';

const _paymentItems = [
  PaymentItem(
    label: 'Total',
    amount: '99.99',
    status: PaymentItemStatus.final_price,
  )
];

ApplePayButton(
  paymentConfiguration: PaymentConfiguration.fromJsonString(
      defaultApplePayConfigString),
  paymentItems: _paymentItems,
  style: ApplePayButtonStyle.black,
  type: ApplePayButtonType.buy,
  margin: const EdgeInsets.only(top: 15.0),
  onPaymentResult: onApplePayResult,
  loadingIndicator: const Center(
    child: CircularProgressIndicator(),
  ),
),

GooglePayButton(
  paymentConfiguration: PaymentConfiguration.fromJsonString(
      defaultGooglePayConfigString),
  paymentItems: _paymentItems,
  type: GooglePayButtonType.buy,
  margin: const EdgeInsets.only(top: 15.0),
  onPaymentResult: onGooglePayResult,
  loadingIndicator: const Center(
    child: CircularProgressIndicator(),
  ),
),

void onApplePayResult(paymentResult) {
  // Send the resulting Apple Pay token to your server / PSP
}

void onGooglePayResult(paymentResult) {
  // Send the resulting Google Pay token to your server / PSP
}

Alternative methods to load your payment configurations

JSON strings

The example above uses the PaymentConfiguration.fromJsonString method to load your payment configuration from a string in JSON format (example). This configuration can be retrieved from a remote location at runtime (recommended) or provided at build time.

Asset files

You can also place payment configurations under your assets folder and load them at runtime. Suppose that you add a JSON file with the name google_pay_config.json to your assets folder to configure your Google Pay integration. You can load it and use it to create a PaymentConfiguration object for the button (e.g.: using a FutureBuilder):

final Future<PaymentConfiguration> _googlePayConfigFuture = 
    PaymentConfiguration.fromAsset('google_pay_config.json');

FutureBuilder<PaymentConfiguration>(
    future: _googlePayConfigFuture,
    builder: (context, snapshot) => snapshot.hasData
        ? GooglePayButton(
          paymentConfiguration: snapshot.data!,
          paymentItems: _paymentItems,
          type: GooglePayButtonType.buy,
          margin: const EdgeInsets.only(top: 15.0),
          onPaymentResult: onGooglePayResult,
          loadingIndicator: const Center(
            child: CircularProgressIndicator(),
          ),
        )
        : const SizedBox.shrink()),

Advanced usage

If you prefer to have more control over each individual request and the button separately, you can instantiate a payment client and add the buttons to your layout independently:

import 'package:pay/pay.dart';

const _paymentItems = [
  PaymentItem(
    label: 'Total',
    amount: '99.99',
    status: PaymentItemStatus.final_price,
  )
];

final Pay _payClient = Pay({
  PayProvider.google_pay: payment_configurations.defaultGooglePayConfig,
  PayProvider.apple_pay: payment_configurations.defaultApplePayConfig,
});

As you can see, you can add multiple configurations to your payment client, one for each payment provider supported.

Now, you can use the userCanPay method to determine whether the user can start a payment process with a given provider. This call returns a Future<bool> result that you can use to decide what to do next. For example, you can feed the Future to a FutureBuilder that shows a different UI based on the result of the call:

@override
Widget build(BuildContext context) {
  return FutureBuilder<bool>(
    future: _payClient.userCanPay(PayProvider.google_pay),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        if (snapshot.data == true) {
          return RawGooglePayButton(
              paymentConfiguration:
                  payment_configurations.defaultGooglePayConfig,
              type: GooglePayButtonType.buy,
              onPressed: _onGooglePayPressed);
        } else {
          // userCanPay returned false
          // Consider showing an alternative payment method
        }
      } else {
        // The operation hasn't finished loading
        // Consider showing a loading indicator 
      }
    },
  );
}

Finally, handle the onPressed event and trigger the payment selector as follows:

void _onGooglePayPressed() async {
  final result = await _payClient.showPaymentSelector(
    PayProvider.google_pay,
    _paymentItems,
  );
  // Send the resulting Google Pay token to your server / PSP
}

Handling a payment result response (Android only)

On Android, payment results are received using an event channel, in order to eliminate the effect of lost references during activity recreation events. Because of that, calls to Pay.showPaymentSelector only initiate the payment process and don't return any result.

To subscribe to the result stream, create an EventChannel using the payment results channel name (plugins.flutter.io/pay/payment_result) and start listening to events:

static const eventChannel =
    EventChannel('plugins.flutter.io/pay/payment_result');
final _paymentResultSubscription = eventChannel
    .receiveBroadcastStream()
    .map((result) => jsonDecode(result as String) as Map<String, dynamic>)
    .listen((result) {
      // TODO: Send the resulting Google Pay token to your server / PSP
    }, onError: (error) {
      // TODO: Handle errors
    });

Make sure to cancel the subscription and clear the reference when it is not needed anymore:

_paymentResultSubscription.cancel();
_paymentResultSubscription = null;

See the advanced example to see a working integration.

Additional resources

Take a look at the following resources to manage your payment accounts and learn more about the APIs for the supported providers:

Google Pay Apple Pay
Platforms  Android  iOS
 Documentation  Overview Overview
 Console  Google Pay Business Console Developer portal
Reference API reference  Apple Pay API
Style guidelines  Brand guidelines Buttons and Marks

Note: This is not an officially supported Google product.

Libraries

pay