Google Pay API สำหรับ Jetpack Compose ใน Android

1. บทนำ

สิ่งที่คุณจะสร้าง

เมื่อทำ Codelab นี้เสร็จแล้ว คุณจะมีแอป Jetpack Compose ที่นำเสนอเพียงคุณสมบัติหลักๆ พร้อมการผสานรวม Google Pay ที่ใช้งานได้สำหรับ Android โปรเจ็กต์นี้จะดึงโทเค็นการชำระเงินซึ่งอาจส่งไปยังผู้ให้บริการชำระเงินเพื่อประมวลผล

สิ่งที่คุณจะได้เรียนรู้

  • วิธีติดตั้งและกำหนดค่าไลบรารี Jetpack Compose ของ Google Pay
  • วิธีแสดงปุ่ม Google Pay และจัดการการคลิก
  • วิธีขอโทเค็นการชำระเงินจาก Google Pay

สิ่งที่คุณต้องมี

  • ติดตั้ง Android Studio (เสถียรล่าสุด) แล้ว
  • Android SDK และโปรแกรมจำลองหรืออุปกรณ์ที่ตั้งค่าใน Android Studio
  • สำหรับเวอร์ชันที่ใช้งานจริง คุณจะต้องมี Google Pay merchantId การลงทะเบียนใน Google Pay และ Wallet Console ใช้เวลาเพียง 1 นาที ดังนั้นคุณควรดำเนินการให้เรียบร้อยในตอนนี้

2. สร้างโปรเจ็กต์ Jetpack Compose

สร้างไฟล์โปรเจ็กต์

  1. สร้างโปรเจ็กต์ Jetpack Compose ใหม่ใน Android Studio ชื่อ gpay-compose
      โดยทำดังนี้
    • เปิด Android Studio แล้วเลือก New Project
    • เลือกเทมเพลต Empty Activity (Jetpack Compose)
    • ชื่อ: gpay-compose, ชื่อแพ็กเกจ: com.example.gpay
    • ภาษา: Kotlin, SDK ขั้นต่ำ: API 21 ขึ้นไป
    • เสร็จสิ้นเพื่อสร้างโปรเจ็กต์
  2. เพิ่มทรัพยากร Dependency ของปุ่ม 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. เพิ่มทรัพยากร Dependency ของ Google Play services Wallet (เพื่อเปิดชีต Google Pay): เพิ่มทรัพยากร Dependency ต่อไปนี้ในไฟล์ 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. เปิด MainActivity.kt ใน Android Studio แล้วแทนที่เนื้อหาด้วยโครงสร้างแอป 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(...) จะสร้าง PaymentDataRequest โดยเพิ่ม transactionInfo ลงใน baseGooglePayRequest เปิดชีต Google Pay และแสดงโทเค็นการชำระเงิน

ข้อมูลสำคัญ

  • ปุ่ม: PayButton แสดงปุ่ม Google Pay ดั้งเดิม
  • ไคลเอ็นต์: PaymentsClient ได้รับการกำหนดค่าด้วย TEST หรือ PRODUCTION
  • เปิดตัว: ใช้ loadPaymentData และแก้ไขด้วย IntentSender เมื่อจำเป็น
  • โทเค็น: แยกวิเคราะห์ PaymentData.toJson() เพื่อดึงข้อมูล paymentMethodData.tokenizationData.token และส่งไปยัง PSP

6. บทสรุป

ขอแสดงความยินดีที่ทำ Codelab นี้เสร็จสมบูรณ์ คุณได้เรียนรู้วิธีผสานรวม Google Pay API เข้ากับแอป Jetpack Compose สำหรับ Android แล้ว

เรียกใช้โปรเจ็กต์

เรียกใช้โปรเจ็กต์จาก Android Studio (Run > Run 'app') เพื่อเริ่มแอป

ขั้นตอนถัดไป

แหล่งข้อมูลเพิ่มเติม