Skip to main content

Google Pay – Flutter SDK

This guide describes how to integrate Nium's Google Pay push provisioning SDK into a Flutter application through an Android platform channel. It covers Android dependencies, native SDK integration, provisioning, and provisioning-status checks.

For the native Android SDK flow, see Google Pay – Push Provisioning.

Before you begin

Confirm with Nium that your card program is enabled for Google Wallet push provisioning and obtain the approved SDK artifacts and integration instructions. The Kotlin package names, SDK initialization signature, callback types, and model properties below must be checked against the SDK version supplied to your team.

Do not embed a confidential server-side apiSecret in an Android application. Confirm the supported mobile authentication or backend-mediated credential mechanism with Nium before production integration.

Prerequisites​

  • A Flutter project with an Android application module and a configured Android development environment.
  • Access to the Nium Android push provisioning SDK and its required dependencies.
  • A supported Android device with Google Wallet and the required Google Play services capabilities.
  • An eligible card and the identifiers required by your Nium integration, including cardHashId.
  • The Android SDK's supported minimum API level, Gradle requirements, and initialization credentials, confirmed against the version provided by Nium.

Step 1: Create a Flutter project​

Run the following commands:

flutter create google_push_provisioning_demo
cd google_push_provisioning_demo

Open the project in your preferred IDE, such as Android Studio or VS Code.

Step 2: Add the Android SDK dependencies​

Copy the SDK artifacts​

Create the android/app/libs directory and copy the SDK files supplied by Nium into it:

mkdir -p android/app/libs
cp /path/to/NiumPushPay_SDK.aar android/app/libs/
cp /path/to/play-services-tapandpay-17.0.1.aar android/app/libs/

Replace /path/to/ with the actual location of the files. The filenames shown are from the existing integration instructions; confirm the current filenames and approved Tap and Pay dependency version with Nium.

Configure Gradle​

If your Android application uses Kotlin DSL, add the local AAR repository to the app module's repository configuration in android/app/build.gradle.kts, subject to your project's repository-management policy:

repositories {
flatDir {
dirs("libs")
}
}

dependencies {
implementation(name = "NiumPushPay_SDK", ext = "aar")
implementation(name = "play-services-tapandpay-17.0.1", ext = "aar")
}
Gradle configuration

The repository and dependency declarations above are an illustration for projects that permit module-level repositories. Some recent Flutter/Gradle projects centralize repositories in settings.gradle.kts and reject module-level declarations. In those projects, configure the repository in the permitted location and point it to android/app/libs.

The dependency name must match the actual .aar filename (without .aar). Confirm whether Nium distributes the artifact as NiumPushPay_SDK.aar or under a different name. Local AAR dependencies may not automatically resolve transitive dependencies.

Step 3: Connect Flutter to the Android SDK​

Flutter uses a MethodChannel to request provisioning operations from native Android code. The channel name and method names must match on both sides.

Flutter method channel​

The following Dart example sends a card identifier to Android and receives the result. Replace the placeholder card identifier with a value retrieved through your authorized card-management flow.

Update lib/main.dart:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return const MaterialApp(home: HomePage());
}
}

class HomePage extends StatefulWidget {
const HomePage({super.key});

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
static const MethodChannel _channel = MethodChannel('push_provisioning');
bool _isProcessing = false;
String _status = '';

Future<void> provisionCard(String cardHashId) async {
setState(() => _isProcessing = true);
try {
final result = await _channel.invokeMapMethod<String, dynamic>(
'provisionCard',
{'cardHashId': cardHashId},
);
if (mounted) {
setState(() => _status = 'Provisioning completed: ${result?['success']}');
}
} on PlatformException catch (error) {
if (mounted) {
setState(() => _status = 'Provisioning failed: ${error.message}');
}
} finally {
if (mounted) setState(() => _isProcessing = false);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Google Wallet provisioning')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: _isProcessing
? null
: () => provisionCard('REPLACE_WITH_CARD_HASH_ID'),
child: const Text('Add to Google Wallet'),
),
Text(_status),
],
),
),
);
}
}

Android method-channel handler​

Update android/app/src/main/kotlin/<your-package-path>/MainActivity.kt to connect Flutter's requests to the Nium SDK.

SDK-specific code requires verification

The native Kotlin example below follows the method and callback names in the existing Nium guide. It is not guaranteed to compile against every SDK release. In particular, verify the imports, initialization API, callback interfaces, and model fields against the SDK distributed by Nium. Obtain the approved initialization/authentication example from Nium rather than placing a confidential API secret in the app.

package com.example.google_push_provisioning_demo

import android.content.Intent
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

// Verify these imports against your Nium SDK artifact.
import com.nium.pushpay.sdk.NiumPushPay
import com.nium.pushpay.sdk.listeners.CardListResultListener
import com.nium.pushpay.sdk.listeners.CardResultListener
import com.nium.pushpay.sdk.listeners.PushProvisioningListener
import com.nium.pushpay.sdk.models.CardResultEntity
import com.nium.pushpay.sdk.models.ErrorEntity

class MainActivity : FlutterActivity() {
private val channelName = "push_provisioning"

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

// Initialize the SDK using Nium's approved mobile-safe integration.
// The SDK initialization signature and credential flow must be
// confirmed before enabling the operations below.

MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channelName)
.setMethodCallHandler { call, result ->
when (call.method) {
"provisionCard" -> {
val cardHashId = call.argument<String>("cardHashId")
if (cardHashId.isNullOrBlank()) {
result.error("INVALID_ARGUMENT", "cardHashId is required", null)
return@setMethodCallHandler
}

NiumPushPay.getInstance().addToWallet(
cardHashId,
object : PushProvisioningListener {
override fun onPushProvisioningSuccess(
tokenId: String,
cardHashId: String
) {
runOnUiThread {
result.success(
mapOf("success" to true, "cardHashId" to cardHashId)
)
}
}

override fun onPushProvisioningFailure(errorEntity: ErrorEntity) {
runOnUiThread {
result.error("PROVISION_FAILED", errorEntity.errMsg, null)
}
}
}
)
}

"checkCardStatus" -> {
val cardHashId = call.argument<String>("cardHashId")
if (cardHashId.isNullOrBlank()) {
result.error("INVALID_ARGUMENT", "cardHashId is required", null)
return@setMethodCallHandler
}

NiumPushPay.getInstance().checkIfCardIsAddedToWallet(
cardHashId,
object : CardResultListener {
override fun onCardStatusSuccess(isCardAddedToWallet: Boolean) {
runOnUiThread {
result.success(
mapOf("isCardAddedToWallet" to isCardAddedToWallet)
)
}
}

override fun onCardStatusFailure(errorEntity: ErrorEntity) {
runOnUiThread {
result.error("STATUS_CHECK_FAILED", errorEntity.errMsg, null)
}
}
}
)
}

"getAllCards" -> {
NiumPushPay.getInstance().getCards(object : CardListResultListener {
override fun onCardStatusSuccess(cards: List<CardResultEntity>) {
// Confirm CardResultEntity field names with the SDK.
// Return only the fields your Flutter UI requires.
runOnUiThread {
result.success(mapOf("cardCount" to cards.size))
}
}

override fun onCardStatusFailure(errorEntity: ErrorEntity) {
runOnUiThread {
result.error("GET_CARDS_FAILED", errorEntity.errMsg, null)
}
}
})
}

else -> result.notImplemented()
}
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Forward activity results as required by the Nium SDK version.
NiumPushPay.getInstance().onActivityResult(requestCode, resultCode, data)
}
}

Provisioning status and button visibility​

Before offering the Add to Google Wallet action, use checkCardStatus to determine whether the card has already been provisioned. Hide or disable the action if the returned isCardAddedToWallet value is true. If the status check fails, show an error or retry option rather than assuming the card is not provisioned.

For a list of cards, use the SDK's getCards operation. The example returns only a count because the card-detail property names in the supplied source have not been verified; map the full results after checking the SDK model.

Step 4: Build and test​

Run the app on a supported Android device:

flutter run

Verify the following scenarios:

  1. An eligible card that has not been provisioned can start the Google Wallet flow.
  2. A successfully provisioned card no longer offers an unnecessary Add to Wallet action.
  3. User cancellation, ineligible cards, and SDK errors are handled without leaving the Flutter UI waiting indefinitely.
  4. Status-check failures and SDK initialization failures display useful messages.
note

Provisioning availability depends on card-program configuration, device capabilities, and Nium's approved SDK integration. Confirm the applicable test environment and test-card setup with Nium.

Troubleshooting​

Android SDK dependencies do not resolve​

  • Check that the .aar files exist in android/app/libs and their filenames match the Gradle dependency declarations.
  • Confirm whether the Flutter project uses build.gradle (Groovy) or build.gradle.kts (Kotlin DSL).
  • Check whether repositories must be configured in settings.gradle.kts instead of the app module.
  • Confirm the required Google Play services dependency and any transitive dependencies with Nium.

SDK initialization or provisioning fails​

  • Confirm that the card program and card are eligible for Google Wallet push provisioning.
  • Verify the approved SDK version, initialization sequence, and mobile-safe authentication flow.
  • Confirm that the Android activity-result callback is forwarded as required by the SDK.
  • Check the SDK's documented error codes and the test environment configuration.

Private repository access​

If the SDK is supplied through a private repository rather than as local .aar files, obtain repository access instructions from Nium. Use your organization's secure credential-management approach; do not place repository usernames, passwords, or access tokens directly in source-controlled Gradle files.

For further assistance, contact your Nium account manager or Nium Support.

LLM-ready documentation:: llms.txt and llms-full.txt
Was this page helpful?