Streamlining Android Payments: Integrating Google Pay with Checkout.com's Flow SDK
Welcome, developers, to a deep dive into modern payment integration on Android. Today, we're dissecting Checkout.com's new Flow Android SDK, a powerful tool designed to simplify how your applications handle payments, particularly with Google Pay. This guide will walk you through setting up an end-to-end payment flow, emphasizing the practical 'how-to' alongside the crucial 'why' behind each step. We'll explore how the Flow SDK helps boost conversions, ensures compliance, and expands your market reach with minimal development effort, all while providing a seamless user experience.

Embracing a Unified Payment Interface
At its core, the Flow SDK is a sophisticated piece of engineering aimed at providing a single, customizable integration point for various payment methods. Dominik Mengelt introduces the challenge developers face: accepting Google Pay on Android and the web requires a reliable payment service provider. Checkout.com steps in with their Flow SDKs, making this process remarkably efficient. Sunghun Jung, Product Manager for Checkout.com's mobile SDKs, highlights the product's main pillars: boosting conversion and acceptance rates through dynamic payment method offerings, ensuring compliance with standards like PCI DSS by keeping sensitive data off merchant servers, and accelerating entry into new markets by continuously integrating new payment methods.
The Flow SDK for web has been a go-to for merchants, and now, the native Android SDK brings all these benefits to app-based customers. This evolution represents a significant leap, offering developers robust tools to handle payment complexities while focusing on their core product.
Prerequisites for a Smooth Integration
Before we dive into the code, it's beneficial to have a foundational understanding of a few key areas:
- Android Development: Familiarity with Android application structure,
Activities,Fragments, and lifecycle management. - Kotlin: The Flow SDK examples are primarily in Kotlin, leveraging its modern features for conciseness and safety.
- Jetpack Compose: Our UI examples will utilize Jetpack Compose, Android's declarative UI toolkit. Basic knowledge of Composables and state management (
StateFlow) will be helpful. - HTTP Requests: An understanding of how to make network requests (e.g., to create payment sessions on your backend).
- Payment Gateway Concepts: Basic knowledge of payment processing, tokens, and payment methods will aid in grasping the overall flow.
Key Libraries and Tools
Integrating payments successfully often involves orchestrating several components. Here are the primary tools and libraries we'll be working with:
- Checkout.com Flow Android SDK: This is the central library for integrating various payment methods, including Google Pay, with Checkout.com's payment gateway. It handles UI rendering, payment method availability checks, and secure data transmission.
- Google Pay API: Although the Flow SDK abstracts much of this, understanding that Google Pay provides an API to check readiness and handle payment sheet interactions is key.
- Android Studio: The official IDE for Android development, providing all the necessary tools for coding, debugging, and running your application.
- Kotlin (with Coroutines): The primary language for Android development, with coroutines enabling asynchronous operations for network calls and background tasks in a clean, structured manner.
- Jetpack Compose: Used for building the user interface, allowing for declarative and reactive UI development.
- Maven Central: The repository from which the Checkout.com Flow SDK dependency is fetched, a standard for distributing Java/Kotlin libraries.
Code Walkthrough: Integrating Google Pay
The integration process with Checkout.com's Flow SDK is divided into several logical steps, moving from your merchant backend to the Android application. Chintan Soni and Fabio Insolia from the Checkout.com team demonstrate this process with clear, step-by-step guidance.
1. Setting Up the Payment Session
The first critical step occurs on your merchant's backend. Before your Android app can initiate a payment, it needs a valid payment session from the Checkout.com server. This is crucial for security, ensuring that sensitive transaction details are handled server-to-server.
Your server makes an API call to Checkout.com, providing details like the amount, currency, and the payment methods you wish to enable (e.g., Google Pay). The response will include a paymentSessionId, token, and secret, which are then securely passed to your Android application.
Here is a conceptual example of a server-side request (note: this is a simplified representation, actual implementation will vary based on your backend language and framework):
{
"amount": 1000,
"currency": "GBP",
"customer": {
"email": "[email protected]"
},
"enabledPaymentMethods": [
{
"type": "googlepay"
},
{
"type": "card"
}
],
"successUrl": "https://your-merchant-app.com/success",
"failureUrl": "https://your-merchant-app.com/failure"
}
2. Integrating the Flow SDK Dependency
Once you have your payment session details, integrate the Flow SDK into your Android project. This is a standard process using Gradle.
In your project-level build.gradle.kts file, ensure Maven Central is included:
// project/build.gradle.kts
plugins {
// ...
}
allprojects {
repositories {
google()
mavenCentral() // Ensure Maven Central is here
}
}
Then, in your app-level build.gradle.kts file, add the Flow SDK dependency:
// app/build.gradle.kts
dependencies {
// ...
implementation("com.checkout.android:checkout-sdk-flow:<latest_version>")
}
3. Configuring the Checkout Component
With the SDK integrated, the next step in your Android application is to prepare the CheckoutComponentConfig. This configuration ties your app to the payment session and defines UI behaviors.
// In your ViewModel or Activity
fun createCheckoutComponent(paymentSessionData: PaymentSessionData) {
val config = CheckoutComponentConfig.Builder(
paymentSessionData.token, // Payment session token from your backend
paymentSessionData.secret, // Payment session secret
this, // Context, typically 'this' for an Activity or ViewModel context
"your_public_key", // Your public key from Checkout.com dashboard
Environment.SANDBOX, // Or Environment.PRODUCTION
componentCallback
)
.build()
// ...
}
The ComponentCallback is crucial for handling lifecycle events of the payment methods:
val componentCallback = object : ComponentCallback {
override fun onReady() {
// The component is ready to be rendered and interacted with
Log.d("Checkout", "Component is ready")
}
override fun onSubmit() {
// User has submitted payment details, typically show a loading indicator
Log.d("Checkout", "Payment submitted")
}
override fun onSuccess(component: PaymentMethodComponent, paymentId: String) {
// Payment was successful, handle the paymentId
Log.d("Checkout", "Payment successful with ID: $paymentId")
// Navigate to success screen or update UI
}
override fun onError(component: PaymentMethodComponent?, error: CheckoutError) {
// An error occurred, display error message to the user
Log.e("Checkout", "Payment error: ${error.message}")
// Handle specific error types if needed
}
}
4. Initializing the Checkout Component Factory
The CheckoutComponentsFactory is the entry point for creating specific payment method components. It's a suspend function, meaning it performs background operations, so it needs to be called within a coroutine scope.
// In your ViewModel
private val _checkoutComponents = MutableStateFlow<CheckoutComponents?>(null)
val checkoutComponents: StateFlow<CheckoutComponents?> = _checkoutComponents
suspend fun initializeCheckoutComponents(paymentSessionData: PaymentSessionData) {
val config = CheckoutComponentConfig.Builder(
paymentSessionData.token,
paymentSessionData.secret,
getApplication(), // Use application context or activity context
"your_public_key",
Environment.SANDBOX,
componentCallback
).build()
try {
_checkoutComponents.value = CheckoutComponentsFactory.create(config)
} catch (e: CheckoutError) {
Log.e("Checkout", "Failed to create CheckoutComponents: ${e.message}")
// Handle initialization error
}
}
5. Integrating Google Pay
Integrating Google Pay involves a specific coordinator to handle its unique lifecycle and activity results. Fabio Insolia demonstrates this crucial piece.
Manifest Configuration: Ensure your AndroidManifest.xml includes the necessary Google Pay metadata.
<application>
<meta-data
android:name="com.google.android.gms.wallet.api.enabled"
android:value="true" />
</application>
GooglePayFlowCoordinator: This component manages the interaction between the Flow SDK and Google Pay's API. It handles aspects like isReadyToPay checks and processing the activity result from the Google Pay payment sheet.
// In your ViewModel
private val _googlePayFlowCoordinator = MutableStateFlow<GooglePayFlowCoordinator?>(null)
val googlePayFlowCoordinator: StateFlow<GooglePayFlowCoordinator?> = _googlePayFlowCoordinator
fun prepareGooglePayCoordinator(activity: ComponentActivity) {
_googlePayFlowCoordinator.value = GooglePayFlowCoordinator(
activity, // Must implement ViewModelStoreOwner, LifecycleOwner, ActivityResultRegistryOwner
::handleGooglePayActivityResult // Lambda for handling activity results
)
}
private fun handleGooglePayActivityResult(resultCode: Int, data: Intent?) {
checkoutComponents.value?.handleActivityForGooglePay(resultCode, data)
}
Notice the GooglePayFlowCoordinator expects a ComponentActivity context, which acts as the ViewModelStoreOwner, LifecycleOwner, and ActivityResultRegistryOwner. The handleActivityForGooglePay function, provided by the SDK, processes the result from the Google Pay activity.
Creating the Google Pay Component: Now, you can create the Google Pay component, passing the coordinator.
// In your ViewModel, after checkoutComponents is initialized
private val _googlePayComponent = MutableStateFlow<GooglePayComponent?>(null)
val googlePayComponent: StateFlow<GooglePayComponent?> = _googlePayComponent
suspend fun createGooglePayComponent(flowCoordinator: GooglePayFlowCoordinator) {
val googlePayConfig = GooglePayComponentConfig.Builder(
CheckoutGooglePayComponentProvider(), // Provider for Google Pay
mapOf(GooglePayFlowCoordinator::class.java to flowCoordinator)
).build()
try {
_googlePayComponent.value = checkoutComponents.value?.createGooglePayComponent(googlePayConfig)
} catch (e: CheckoutError) {
Log.e("Checkout", "Failed to create Google Pay component: ${e.message}")
// Handle error
}
}
Checking Availability and Rendering: Before displaying the Google Pay button, the SDK can check if Google Pay is available on the user's device (isAvailable). This function also handles populating allowed payment methods based on your backend configuration.
// In your ViewModel
private val _isGooglePayAvailable = MutableStateFlow(false)
val isGooglePayAvailable: StateFlow<Boolean> = _isGooglePayAvailable
suspend fun checkGooglePayAvailability() {
_isGooglePayAvailable.value = googlePayComponent.value?.isAvailable() ?: false
}
// In your Composable UI
@Composable
fun PaymentScreen(viewModel: PaymentViewModel) {
val googlePayComponent by viewModel.googlePayComponent.collectAsState()
val isGooglePayAvailable by viewModel.isGooglePayAvailable.collectAsState()
LaunchedEffect(viewModel) {
viewModel.checkGooglePayAvailability()
}
if (isGooglePayAvailable) {
googlePayComponent?.Render() // Renders the Google Pay button
} else {
Text("Google Pay not available or checking...")
}
}
The Render() function, when called on a payment method component, generates the appropriate composable UI element (like the Google Pay button). For those still using XML layouts, the SDK also provides a provideView method, where you can pass a container, and it will return the corresponding View.
6. Integrating Other Payment Methods (e.g., Card)
The beauty of the Flow SDK is its consistency. Adding other payment methods, such as a credit card form, follows a similar pattern:
// In your ViewModel, after checkoutComponents is initialized
private val _cardComponent = MutableStateFlow<CardComponent?>(null)
val cardComponent: StateFlow<CardComponent?> = _cardComponent
suspend fun createCardComponent() {
val cardConfig = CardComponentConfig.Builder().build()
try {
_cardComponent.value = checkoutComponents.value?.createCardComponent(cardConfig)
} catch (e: CheckoutError) {
Log.e("Checkout", "Failed to create Card component: ${e.message}")
}
}
// In your Composable UI
@Composable
fun CardPaymentSection(viewModel: PaymentViewModel) {
val cardComponent by viewModel.cardComponent.collectAsState()
LaunchedEffect(viewModel) {
viewModel.createCardComponent()
}
cardComponent?.Render() // Renders the card input form
}
This modular approach allows developers to easily swap or combine various payment methods, offering a customized checkout experience without rebuilding core logic.
Syntax Notes
Throughout the integration, you'll observe several modern Kotlin and Android development patterns:
- Kotlin Coroutines (
suspendfunctions andLaunchedEffect): Many operations, especially network calls and factory creation, aresuspendfunctions. These enable asynchronous programming without callback hell, keeping code readable and sequential.LaunchedEffectin Compose is used to trigger side effects (like data fetching) that should run within a Composable's lifecycle. - Jetpack Compose (
@Composable,StateFlow): The UI is built using declarative Composables.MutableStateFlowandStateFloware used in theViewModelto expose data that the UI can observe and react to, triggering recomposition when values change. - Lambda Expressions: Used extensively for callbacks, such as the
ComponentCallbackand for handling activity results, making the code more functional and concise.
Practical Examples
The Flow SDK's design makes it suitable for a wide array of real-world applications:
- E-commerce Mobile Apps: Quickly integrate a secure, compliant, and customizable checkout flow for physical or digital goods.
- Subscription Services: Streamline the signup process by offering popular payment methods, ensuring higher conversion rates.
- On-demand Services: Facilitate fast and reliable payments for ride-sharing, food delivery, or other instant services.
- Global Marketplaces: Leverage the SDK's ability to offer region-specific and alternative payment methods, reaching a broader international customer base.
Tips and Gotchas
As with any robust SDK, there are best practices and common pitfalls to be aware of:
- Server-Side Payment Session Creation: Always create the payment session on your secure backend. Exposing API keys or secrets directly in your client-side application is a significant security risk.
- Google Pay Metadata: Remember to include the
com.google.android.gms.wallet.api.enabledmetadata in yourAndroidManifest.xmlfor Google Pay functionality to work correctly. GooglePayFlowCoordinatoris Essential: For Google Pay, theGooglePayFlowCoordinatoris not optional. It's vital for correctly managing the Google Pay activity lifecycle and processing results.- Robust Error Handling: Utilize the
onErrorcallback inComponentCallbackto provide meaningful feedback to users and log details for debugging. The Flow SDK provides specificCheckoutErrortypes that can be handled gracefully. - Customization Flexibility: While the SDK provides ready-to-use UI components, you have extensive control over styling and layout. You can integrate individual payment method components into your existing UI structure as needed.
- PCI DSS Compliance: The Flow SDK is designed to help merchants achieve and maintain PCI DSS compliance by securely handling sensitive card data directly with Checkout.com's servers, reducing your direct burden.
- Fraud Prevention: The SDK incorporates features like device fingerprinting to help detect and prevent fraudulent transactions, adding another layer of security.
- 3D Secure Automation: A standout feature is the SDK's automatic handling of 3D Secure challenges, even for Google Pay transactions if the chosen funding instrument requires it. This simplifies a complex security requirement for developers.
- Multi-Platform Strategy: While native Android and iOS SDKs are fully supported, for Flutter or React Native applications, consider the documented bridge approach using the native SDKs. Checkout.com has plans to introduce official SDKs for these platforms in the future.
- Beyond Payments (Payouts and Tokenization): The Flow SDK isn't just for collecting payments. It also supports tokenization-only mode, allowing you to securely capture card details and receive a token. This token can then be used for subsequent transactions, including merchant-initiated transactions like payouts, giving you more control over your payment workflows.
By following these guidelines and leveraging the power of the Checkout.com Flow Android SDK, you can significantly streamline your payment integration process, delivering a secure, flexible, and user-friendly experience to your customers.
Happy coding!