Android 上的 Jetpack Compose 的 Google Pay API

1. 简介

构建内容

完成此 Codelab 后,您将拥有一个最低可行性 Jetpack Compose 应用,其中包含适用于 Android 的 Google Pay 集成。此项目会检索付款令牌,该令牌可能会发送给付款服务提供商进行处理。

学习内容

  • 如何安装和配置 Google Pay Jetpack Compose 库
  • 如何显示 Google Pay 按钮并处理点击事件
  • 如何向 Google Pay 请求付款令牌

所需条件

  • 已安装 Android Studio(最新稳定版)。
  • 已在 Android Studio 中设置 Android SDK 和模拟器或设备。
  • 对于生产环境,您需要 Google Pay merchantId。在 Google Pay & Wallet Console 中注册只需一分钟,因此不妨现在就完成注册。

2. 创建 Jetpack Compose 项目

创建项目文件

  1. 在 Android Studio 中创建一个名为 gpay-compose 的新 Jetpack Compose 项目:
    • 打开 Android Studio,然后选择 New Project
    • 选择 Empty Activity (Jetpack Compose) 模板。
    • 名称:gpay-compose,软件包名称:com.example.gpay
    • 语言:Kotlin,最低 SDK 版本:API 21+。
    • 点击“Finish”以生成项目。
  2. 添加 Google Pay Compose 按钮依赖项。在 app/build.gradle(.kts) 文件中,添加:
    dependencies {
        implementation("com.google.pay.button:compose-pay-button:1.0.0")
    }
    
    Groovy DSL:
    dependencies {
        implementation 'com.google.pay.button:compose-pay-button:1.0.0'
    }
    
  3. 添加 Google Play 服务钱包依赖项(以打开 Google Pay 界面):在 app/build.gradle(.kts) 文件中,添加以下依赖项:
    dependencies {
        implementation("com.google.android.gms:play-services-wallet:19.3.0")
    }
    
    如果您的项目使用 Groovy DSL,请使用:
    dependencies {
        implementation 'com.google.android.gms:play-services-wallet:19.3.0'
    }
    
  4. 在 Android Studio 中打开 MainActivity.kt,然后将内容替换为以下最小 Compose 应用框架(我们将在下一步中连接按钮):
    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. 配置 Google Pay

Google Pay 付款请求需要请求对象。此处定义为 baseGooglePayRequest 的对象包含所有请求的最低通用设置。我们将在此 Codelab 中查看,并根据发出的请求添加其他设置。

将 Google Pay 配置常量添加到 MainActivity.kt(您将在下一步中重复使用这些常量):

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()

资源

  • API 参考文档:Google Pay API 请求对象文档
  • API 参考文档:如需详细了解允许的授权方法、允许的卡网络和令牌化规范(包括正确的网关值),请参阅 PaymentMethod

4. 添加 Google Pay 按钮

使用 Compose Pay 按钮呈现原生 Google Pay 按钮,并使用 Wallet API 打开 Google Pay 界面。

MainActivity.kt 的全部内容替换为以下完整示例(包括配置 + 按钮 + 付款流程):

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. 发出付款请求

按下 Google Pay 按钮后,requestPayment(...) 会通过将 transactionInfo 添加到您的 baseGooglePayRequest 来构建 PaymentDataRequest,打开 Google Pay 界面,并返回付款令牌。

要点

  • 按钮:PayButton 呈现原生 Google Pay 按钮。
  • 客户端:PaymentsClient 配置为 TEST 或 PRODUCTION。
  • 启动:使用 loadPaymentData,并在需要时使用 IntentSender 解析。
  • 令牌:解析 PaymentData.toJson() 以提取 paymentMethodData.tokenizationData.token 并发送给您的 PSP。

6. 总结

恭喜您完成此 Codelab!您已了解如何将 Google Pay API 集成到适用于 Android 的 Jetpack Compose 应用中。

运行项目

从 Android Studio 运行项目(Run > Run 'app')以启动应用。

后续步骤

其他资源