1. 簡介
建構項目
完成本程式碼研究室後,您將擁有最低可行的 Jetpack Compose 應用程式,並整合可運作的 Android 版 Google Pay。這個專案會擷取付款權杖,並傳送給付款服務供應商進行處理。
課程內容
- 如何安裝及設定 Google Pay Jetpack Compose 程式庫
- 如何顯示 Google Pay 按鈕及處理點擊事件
- 如何向 Google Pay 申請付款權杖
軟硬體需求
- 已安裝 Android Studio (最新穩定版)。
- Android SDK,以及在 Android Studio 中設定的模擬器或裝置。
- 如要使用正式版,您需要 Google Pay
merchantId。在 Google Pay 和錢包主控台註冊只需一分鐘,不妨現在就完成註冊。
2. 建立 Jetpack Compose 專案
建立專案檔案
- 在 Android Studio 中建立名為
gpay-compose的新 Jetpack Compose 專案:- 開啟 Android Studio,然後選取
New Project。 - 選擇
Empty Activity (Jetpack Compose)範本。 - 名稱:
gpay-compose,套件名稱:com.example.gpay。 - 語言:Kotlin,最低 SDK:API 21 以上版本。
- 完成後即可生成專案。
- 開啟 Android Studio,然後選取
- 新增 Google Pay Compose 按鈕依附元件。在
app/build.gradle(.kts)檔案中新增: Groovy DSL:dependencies { implementation("com.google.pay.button:compose-pay-button:1.0.0") }dependencies { implementation 'com.google.pay.button:compose-pay-button:1.0.0' } - 新增 Google Play 服務錢包依附元件 (開啟 Google Pay 結帳頁面):在
app/build.gradle(.kts)檔案中新增下列依附元件: 如果專案使用 Groovy DSL,請使用:dependencies { implementation("com.google.android.gms:play-services-wallet:19.3.0") }dependencies { implementation 'com.google.android.gms:play-services-wallet:19.3.0' } - 在 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) 包含所有要求的最低通用設定。我們會根據提出的要求新增其他設定,並在程式碼研究室中進行檢查。
將 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 Button 算繪原生 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 畫面,並傳回付款權杖。
重點
- Button:
PayButton會算繪原生 Google Pay 按鈕。 - 用戶端:
PaymentsClient已設定為 TEST 或 PRODUCTION。 - 啟動:使用
loadPaymentData,並在必要時以IntentSender解決問題。 - 權杖:剖析
PaymentData.toJson()以擷取paymentMethodData.tokenizationData.token,然後傳送給 PSP。
6. 結語
恭喜您完成本程式碼研究室!您已瞭解如何將 Google Pay API 整合至 Android 的 Jetpack Compose 應用程式。
執行專案
從 Android Studio (Run > Run 'app') 執行專案,啟動應用程式。
下一步該做什麼?
其他資源
- 在 Discord 的 #payments 頻道中加入對話
- 在 X 上追蹤 @GooglePayDevs
- 在 YouTube 觀看 Google Pay 相關影片