API Google Pay pour Jetpack Compose sur Android

1. Introduction

Objectifs de l'atelier

À la fin de cet atelier de programmation, vous disposerez d'une application Jetpack Compose viable minimale avec une intégration Google Pay fonctionnelle pour Android. Ce projet récupère un jeton de paiement qui peut être envoyé à un fournisseur de services de paiement pour traitement.

Points abordés

  • Installer et configurer la bibliothèque Google Pay Jetpack Compose
  • Afficher le bouton Google Pay et gérer les clics
  • Demander un jeton de paiement à Google Pay

Ce dont vous avez besoin

  • Android Studio (dernière version stable) installé.
  • SDK Android et émulateur ou appareil configuré dans Android Studio.
  • Pour la production, vous aurez besoin d'un Google Pay merchantId. L'inscription à la Google Pay & Wallet Console ne prend qu'une minute. Vous pouvez donc le faire dès maintenant.

2. Créer le projet Jetpack Compose

Créer des fichiers de projet

  1. Créez un projet Jetpack Compose dans Android Studio nommé gpay-compose:
    • Ouvrez Android Studio, puis sélectionnez New Project (Nouveau projet).
    • Choisissez le modèle Empty Activity (Jetpack Compose).
    • Nom : gpay-compose, nom du package : com.example.gpay.
    • Langue : Kotlin, SDK minimal : API 21+.
    • Cliquez sur "Finish" (Terminer) pour générer le projet.
  2. Ajoutez la dépendance du bouton Google Pay Compose.Dans le fichier app/build.gradle(.kts), ajoutez :
    dependencies {
        implementation("com.google.pay.button:compose-pay-button:1.0.0")
    }
    
    DSL Groovy :
    dependencies {
        implementation 'com.google.pay.button:compose-pay-button:1.0.0'
    }
    
  3. Ajoutez la dépendance Google Play Services Wallet (pour ouvrir la fiche Google Pay) : dans le fichier app/build.gradle(.kts), ajoutez la dépendance suivante :
    dependencies {
        implementation("com.google.android.gms:play-services-wallet:19.3.0")
    }
    
    Si votre projet utilise le DSL Groovy, utilisez :
    dependencies {
        implementation 'com.google.android.gms:play-services-wallet:19.3.0'
    }
    
  4. Ouvrez MainActivity.kt dans Android Studio et remplacez le contenu par la structure d'application Compose minimale suivante (nous connecterons le bouton ensuite) :
    package com.example.gpay
    
    import android.os.Bundle
    import androidx.activity.ComponentActivity
    import androidx.activity.compose.setContent
    import androidx.compose.foundation.layout.Box
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.material3.MaterialTheme
    import androidx.compose.material3.Surface
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    
    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                        // Google Pay button added in the next section
                    }
                }
            }
        }
    }
    

3. Configurer Google Pay

Une demande de paiement Google Pay nécessite un objet de requête. L'objet défini ici comme baseGooglePayRequest contient les paramètres communs minimaux pour toutes les requêtes. Des paramètres supplémentaires seront ajoutés en fonction de la requête effectuée, que nous examinerons dans cet atelier de programmation.

Ajoutez les constantes de configuration Google Pay à MainActivity.kt (vous les réutiliserez à l'étape suivante) :

private const val merchantId = "12345678901234567890"

// This is the base configuration for all Google Pay payment data requests.
private val baseGooglePayRequest = """
    {
      "apiVersion": 2,
      "apiVersionMinor": 0,
      "allowedPaymentMethods": [
        {
          "type": "CARD",
          "parameters": {
            "allowedAuthMethods": [
              "PAN_ONLY", "CRYPTOGRAM_3DS"
            ],
            "allowedCardNetworks": [
              "AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"
            ]
          },
          "tokenizationSpecification": {
            "type": "PAYMENT_GATEWAY",
            "parameters": {
              "gateway": "example",
              "gatewayMerchantId": "exampleGatewayMerchantId"
            }
          }
        }
      ],
      "merchantInfo": {
        "merchantId": "$merchantId"
      }
    }
""".trimIndent()

Ressources

  • Documentation de référence sur les API : documentation sur les objets de requête de l'API Google Pay
  • Documentation de référence sur les API : consultez PaymentMethod pour en savoir plus sur les méthodes d'autorisation autorisées, les réseaux de cartes autorisés et les spécifications de tokenisation, y compris la valeur de passerelle appropriée.

4. Ajouter le bouton Google Pay

Utilisez le bouton Compose Pay pour afficher un bouton Google Pay natif et l'API Wallet pour ouvrir la fiche Google Pay.

Remplacez l'intégralité du contenu de MainActivity.kt par l'exemple complet suivant (inclut la configuration, le bouton et le flux de paiement) :

package com.example.gpay

import android.os.Bundle
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.tasks.Task
import com.google.android.gms.wallet.contract.TaskResultContracts.GetPaymentDataResult
import com.google.android.gms.wallet.*
import com.google.pay.button.ButtonTheme
import com.google.pay.button.ButtonType
import com.google.pay.button.PayButton
import org.json.JSONObject

private const val merchantId = "12345678901234567890"

// Base Google Pay request used for both the button and the Wallet request
private val baseGooglePayRequest = """
    {
      "apiVersion": 2,
      "apiVersionMinor": 0,
      "allowedPaymentMethods": [
        {
          "type": "CARD",
          "parameters": {
            "allowedAuthMethods": [
              "PAN_ONLY", "CRYPTOGRAM_3DS"
            ],
            "allowedCardNetworks": [
              "AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"
            ]
          },
          "tokenizationSpecification": {
            "type": "PAYMENT_GATEWAY",
            "parameters": {
              "gateway": "example",
              "gatewayMerchantId": "exampleGatewayMerchantId"
            }
          }
        }
      ],
      "merchantInfo": {
        "merchantId": "$merchantId"
      }
    }
""".trimIndent()

class MainActivity : ComponentActivity() {
  private val paymentDataLauncher = registerForActivityResult(GetPaymentDataResult()) { taskResult ->
    when (taskResult.status.statusCode) {
      CommonStatusCodes.SUCCESS -> {
        handlePaymentData(taskResult.result!!)
      }
      //CommonStatusCodes.CANCELED -> The user canceled
      //CommonStatusCodes.DEVELOPER_ERROR -> The API returned an error (it.status: Status)
      //else -> Handle internal and other unexpected errors
    }
  }
  private lateinit var paymentsClient: PaymentsClient

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Create the PaymentsClient
    paymentsClient = Wallet.getPaymentsClient(
      this,
      Wallet.WalletOptions.Builder()
        .setEnvironment(WalletConstants.ENVIRONMENT_TEST) // Switch to PRODUCTION when ready
        .build()
    )

    // Derive allowedPaymentMethods for the button from baseGooglePayRequest
    val allowedPaymentMethods = JSONObject(baseGooglePayRequest)
      .getJSONArray("allowedPaymentMethods")
      .toString()

    setContent {
      Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        PayButton(
          onClick = { requestPayment(paymentDataLauncher) },
          allowedPaymentMethods = allowedPaymentMethods,
          type = ButtonType.Pay,
          theme = ButtonTheme.Light
        )
      }
    }
  }

  private fun requestPayment(launcher: ActivityResultLauncher<Task<PaymentData>>) {
    // Build a PaymentDataRequest from the base request by adding transaction info
    val requestJson = JSONObject(baseGooglePayRequest).apply {
      put("transactionInfo", JSONObject().apply {
        put("totalPrice", "14.95")
        put("totalPriceStatus", "FINAL")
        put("countryCode", "US")
        put("currencyCode", "USD")
      })
    }
    val request = PaymentDataRequest.fromJson(requestJson.toString())
    val task = paymentsClient.loadPaymentData(request)
    task.addOnCompleteListener(paymentDataLauncher::launch)
  }

  private fun handlePaymentData(paymentData: PaymentData?) {
    val json = paymentData?.toJson() ?: return
    val paymentMethodData = JSONObject(json).getJSONObject("paymentMethodData")
    val tokenizationData = paymentMethodData.getJSONObject("tokenizationData")
    val token = tokenizationData.getString("token")
    // Send 'token' to your payment service provider (PSP)
    println("Payment token: $token")
  }
}

5. Effectuer une demande de paiement

Lorsque vous appuyez sur le bouton Google Pay, requestPayment(...) crée un PaymentDataRequest en ajoutant transactionInfo à votre baseGooglePayRequest, ouvre la fiche Google Pay et renvoie un jeton de paiement.

Points essentiels

  • Bouton : PayButton affiche le bouton Google Pay natif.
  • Client : PaymentsClient est configuré avec TEST ou PRODUCTION.
  • Lancement : utilisez loadPaymentData et résolvez avec un IntentSender si nécessaire.
  • Jeton : analysez PaymentData.toJson() pour extraire paymentMethodData.tokenizationData.token et envoyez-le à votre PSP.

6. Conclusion

Félicitations ! Vous avez terminé cet atelier de programmation. Vous avez appris à intégrer l'API Google Pay dans une application Jetpack Compose pour Android.

Exécuter le projet

Exécutez le projet à partir d'Android Studio (Run > Run 'app') pour démarrer votre application.

Étapes suivantes

Ressources supplémentaires