使用 Google Pay (Kotlin) 在 Android 打造快速結帳體驗

1. 簡介

Google Pay API 會運用使用者儲存在 Google 帳戶中的付款資訊,方便他們隨時隨地輕鬆付款。在本研究室中,您將利用 Android 專用的 Google Pay 用戶端程式庫,建立更快速、便利及安全的結帳程序,讓經過簡化的範例行動應用程式可提供更優質的結帳體驗,同時還能促成更多轉換並提高顧客滿意度。

「Auto T-Shirt Shop」是創新的商店,他們採用人工智慧的最新先進技術,並運用偏好風格、天氣、一年中的不同時節以及時尚趨勢等資訊,為使用者提供最適合購買的商品建議。

參與度相關的指標都有超水準的表現,但遺憾的是,這些數據也反映出結帳過程中的高放棄率。為解決這個問題,其中一位專案擁有者想到曾經觀看一部影片,內容展示 Google Pay 為其他類似網站帶來的出色成果,因此他們決定試試看,並且相信您能處理這項整合作業。

建構目標

本程式碼研究室會逐步說明如何將 Google Pay 整合至現有應用程式,包括判斷使用者能否使用 Google Pay 支援的付款方式付款、放置及設計付款按鈕,以及執行交易。

f5f96f8afc94448c.png

課程內容

  • 如何將 Google Pay 整合至現有應用程式
  • 如何選擇偏好的付款方式
  • 如何判斷使用者能否透過 Google Pay 付款

軟硬體需求

  • 可上網的電腦
  • 適合建構 Android 應用程式的開發環境 (建議使用 Android Studio)
  • 已安裝最新版 Google Play 服務的 Android 裝置

2. 開始操作

從 GitHub 複製存放區:

使用下列指令將存放區複製到電腦的資料夾內:

$ git clone https://github.com/google-pay/android-quickstart

您也可以視需要下載 ZIP 封存檔:

重點瀏覽範例應用程式

如您所見,存放區的檔案結構並不複雜。本程式碼研究室的主要目標是讓您能配合現有和未來的應用程式調整這項整合程序,不受您選擇使用的程式設計語言、程式庫或工具限制。

3. 將 Google Pay 整合至範例應用程式 (或您自己的應用程式)

瞭解應用程式

建構應用程式後,您可以使用模擬器或實體裝置進行預覽。建議您使用已與特定 Google 帳戶和付款方式建立關聯的裝置。

本程式碼研究室建構的應用程式是一間示範行動商店,其中採用極先進的機器學習模型,會根據眾多複雜的特性為訪客建議一件適合的 T 恤。如果您碰巧產生以下疑問:「為什麼每次重新載入網站,該網站都會建議您購買不同的 T 恤?」嗯...老實說,這個極先進的機器學習模型只是一個隨機產生器 (抱歉)。

這個示範商店在建立時,已忠實呈現現有或可能的應用程式外觀樣式,但尚未加入購買程序。事實上,即使我們建議您使用這個示範應用程式進行操作,您仍可以放心運用這個程式碼研究室,將 Google Pay 整合至自己現有的應用程式。

如果您尚未執行示範應用程式以顯示其目前狀態,請立即執行。

175215c8c8696ede.png

看到示範應用程式的畫面後,您應該一點也不感到意外,對吧?產品詳細資料的畫面,提供相片、說明,以及會將您帶往一般付款表單的按鈕。

原則上,本研究室的目標是將這套繁瑣的流程,替換成由 Google Pay 技術輔助、只要輕觸兩下就能完成的使用體驗。

我們來規劃這項程序!

為了深入瞭解這項整合作業,我們將程序分成下列基本步驟:

  1. 新增必要的依附元件
  2. 判斷能否透過 Google Pay 付款
  3. 顯示透過 Google Pay 付款的按鈕
  4. 建立及傳送付款要求
  5. 收集結果

4. 新增必要的依附元件

build.gradle 中新增 Google Play 服務

如要開始使用 Google Pay API,首先需要新增 Google Play 服務內含有所需套件的依附元件,方法是在 build.gradle 檔案的應用程式模組內,將以下 implementation 項目加入 dependencies 清單中。在本程式碼研究室中,這個模組稱為 app

implementation "com.google.android.gms:play-services-wallet:18.0.0"

在資訊清單檔案中啟用這個 API

最後,在資訊清單檔案的 application 節點內新增 meta-data 元素,告知系統您想要使用這個 API 並啟用其存取權:

<meta-data
    android:name="com.google.android.gms.wallet.api.enabled"
    android:value="true" />

5. 規劃使用者介面以及 Google Pay 按鈕的顯示位置

檢視畫面的版面配置和整體使用體驗非常重要,會影響使用者成功完成付款交易的可能性。使用 Google Pay 時,只要輕觸幾下就能選擇付款方式,因此您有更多選項,可決定在應用程式的哪個位置和時機,讓使用者進入付款流程。舉例來說,您可以在程序的初期 (例如商品的詳細資料畫面等區域) 新增快速結帳選項,讓使用者能快速付款購買喜歡的商品。

決定如何安排 UI 和導覽流程後,下一步就是放置按鈕,觸發透過 Google Pay 付款交易的程序。這個按鈕的樣式應遵守特定規範,確保使用者在應用程式看到的按鈕具有一致性和熟悉感:

a18b3311d84d9dcc.png

為方便您完成這項工作,我們已備妥適用於不同解析度和語言代碼的所有選項,加以封裝並提供下載。這個套裝組合包含 layoutdrawablevalues 資源,您可直接貼到專案中。

您可以在 layout 目錄底下,找到需要新增至檢視區塊定義的資源 activity_checkout.xml。如要將按鈕新增至檢視區塊,只要使用 include 元素將其放置在所需位置即可:

<include
    android:id="@+id/googlePayButton"
    layout="@layout/buy_with_googlepay_button"
    android:layout_width=<your_width_dimension>
    android:layout_height="@dimen/buy_button_height"
    android:visibility="gone"/>

6. 初始化及設定 Google Pay API

建立 API 用戶端例項

您需要先為用於呼叫 Google Pay API 的用戶端物件建立例項,才能開始使用這個 API。您可以在建立活動後立即進行這項作業:

private lateinit var paymentsClient: PaymentsClient

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_checkout)

    paymentsClient = createPaymentsClient(this)
}

fun createPaymentsClient(activity: Activity): PaymentsClient {
    val walletOptions = Wallet.WalletOptions.Builder()
            .setEnvironment(WalletConstants.ENVIRONMENT_TEST).build()
    return Wallet.getPaymentsClient(activity, walletOptions)
}

付款用戶端會透過 WalletOptions 物件完成初始化。只要將環境設為 ENVIRONMENT_TEST,即可在整個整合過程中使用虛構付款資訊進行實驗。當您準備好建立支援實際交易的作業時,請將環境屬性更新為 ENVIRONMENT_PRODUCTION

架構

每次與 Google Pay API 通訊時,您都需要在要求中加入多個設定參數,例如指定的 API 版本。以本程式碼研究室為例,這個物件還會包含應用程式接受的付款方式相關資訊。最終結構如下所示:

{
    apiVersion: number,
    apiVersionMinor: number,
    allowedPaymentMethods: Array
}

allowedPaymentMethods 屬性採用一份付款方式清單。您必須為每種付款方式加入下列屬性:

{
    type: 'CARD',
    parameters: {
        allowedCardNetworks: Array.<string>,
        allowedAuthMethods: Array.<string>
    }
}

除了 typeparameters 以外,您稍後會加入 tokenizationSpecification 屬性。這個屬性並非用於判斷使用者能否透過 Google Pay 付款,而是用於 PaymentDataRequest 呼叫,定義所選付款方式相關資料的處理方式。不過,讓我們一步一步來。

設定付款方式

在本範例中,您只要接受以權杖化和主要帳號 (PAN) 形式的 Mastercard 和 Visa 卡片付款。您的付款方式會如下所示:

private val baseCardPaymentMethod = JSONObject().apply {
    put("type", "CARD")
    put("parameters", JSONObject().apply {
        put("allowedCardNetworks", JSONArray(listOf("VISA", "MASTERCARD")))
        put("allowedAuthMethods", JSONArray(listOf("PAN_ONLY", "CRYPTOGRAM_3DS")))
    })
}

總結

複習時間。

您已經定義應用程式可接受的一種付款方式,且即將搭配 2.0 版的 API 運作。產生的設定應如下所示:

private val baseCardPaymentMethod = JSONObject().apply {
    put("type", "CARD")
    put("parameters", JSONObject().apply {
        put("allowedCardNetworks", JSONArray(listOf("VISA", "MASTERCARD")))
        put("allowedAuthMethods", JSONArray(listOf("PAN_ONLY", "CRYPTOGRAM_3DS")))
    })
}

private val googlePayBaseConfiguration = JSONObject().apply {
    put("apiVersion", 2)
    put("apiVersionMinor", 0)
    put("allowedPaymentMethods",  JSONArray().put(baseCardPaymentMethod))
}

現在您已完成基礎設定,接下來進行有趣的部分。

7. 判斷透過 Google Pay 付款的完備性

Google Pay 的其中一個主要目標是為使用者提供更快速便利的結帳體驗。這不僅適用於使用者能夠利用 Google Pay 結帳的情況,也適用於無法使用 Google Pay 的情況。您可以使用 isReadyToPay 要求,判斷透過 Google Pay 付款的完備性,並據以修改網站提供的體驗。

使用者能否透過 Google Pay 付款?

首先,您需要確認即將在應用程式中付款的特定使用者,能否透過 Google Pay 付款。您必須在這項要求中指定 Google Pay API 的版本和網站接受的付款方式。這正是先前步驟所定義基本設定物件包含的內容:

val readyToPayRequest =
        IsReadyToPayRequest.fromJson(googlePayBaseConfiguration.toString())

val readyToPayTask = paymentsClient.isReadyToPay(readyToPayRequest)
task.addOnCompleteListener { task ->
    try {
        task.getResult(ApiException::class.java)?.let(::setGooglePayAvailable)
    } catch (exception: ApiException) {
        // Error determining readiness to use Google Pay.
        // Inspect the logs for more details.
    }
}

如您所見,如果呼叫傳回不成功的回應,就不會採取與 Google Pay 相關的進一步動作。在此情況下,最適合採取的下一個步驟是,另外顯示支援其他付款方式的 UI。

另一方面,如果回應為成功,表示使用者可以透過 Google Pay 付款,享有其快速便利的優點。因此,您可以接著顯示 Google Pay 按鈕,在使用者啟用 (例如點選按鈕) 時啟動付款處理程序。

顯示透過 Google Pay 付款的按鈕

在此階段,您可以繼續進行,在畫面上重新顯示 Google Pay 按鈕:

private fun setGooglePayAvailable(available: Boolean) {
    if (available) {
        googlePayButton.visibility = View.VISIBLE
        googlePayButton.setOnClickListener { requestPayment() }
    } else {
       // Unable to pay using Google Pay. Update your UI accordingly.
    }
}

private fun requestPayment() {
  // TODO: Perform transaction
}

請留意,您同時定義了一個函式,用來處理按鈕點擊事件。在下一節中,您會使用這個函式要求付款方式。

8. 現在要付款了!

準備付款要求

此時,您已載入 Google Pay API,並判定應用程式中的使用者可以透過 Google Pay 付款。因此,您已在 UI 中顯示 Google Pay 付款按鈕,使用者隨時可以啟動交易程序。現在應該載入付款畫面,其中包含不同已登入使用者的可用付款方式。

就像您先前定義 isReadyToPay 要求時執行的操作,這項呼叫也需要使用稍早定義的基本設定物件相關屬性 (apiVersionapiVersionMinorallowedPaymentMethods),以及幾個新屬性。這次有一個名為 tokenizationSpecification 的新屬性,以及僅供此要求使用的相關付款方式額外 parameters,另外還需加入 transactionInfomerchantInfo

加入付款方式的額外必要資訊

首先,建立之前使用過的基本卡片付款方式副本。這個卡片付款方式現在需要 tokenizationSpecification 屬性,定義如何處理所選付款方式相關資料,以及實際交易所需的進一步資料需求:在本範例中,需要完整的帳單地址和電話號碼。

tokenizationSpecification 屬性

權杖化規格決定如何處理使用者所選付款方式,並用於完成交易。

系統支援兩種不同類型的處理策略。如果要在 PCI DSS 相容伺服器內處理付款交易,請使用 DIRECT 規格類型。在本範例中,您使用支付閘道來處理付款,因此要設定 PAYMENT_GATEWAY 規格類型。權杖化規格應如下所示:

private val tokenizationSpecification = JSONObject().apply {
    put("type", "PAYMENT_GATEWAY")
    put("parameters", JSONObject(mapOf(
            "gateway" to "example",
            "gatewayMerchantId" to "exampleGatewayMerchantId")))
}

parameters 區段中,您可以從 Google Pay API 支援的供應商清單中指定閘道,以及個別閘道的其他必要設定。就本研究室而言,使用 example 閘道便足以取得執行交易的測試結果。

其他參數

同樣地,為了成功執行交易,您現在可以提供更多詳細資料,補足要求所需相關資訊。請留意在本範例中,您需要新增 billingAddressRequiredbillingAddressParameters 屬性,表示本次交易需要使用者的完整帳單地址,加上電話號碼。

private val cardPaymentMethod = JSONObject().apply {
    put("type", "CARD")
    put("tokenizationSpecification", tokenizationSpecification)
    put("parameters", JSONObject().apply {
        put("allowedCardNetworks", JSONArray(listOf("VISA", "MASTERCARD")))
        put("allowedAuthMethods", JSONArray(listOf("PAN_ONLY", "CRYPTOGRAM_3DS")))
        put("billingAddressRequired", true)
        put("billingAddressParameters", JSONObject(mapOf("format" to "FULL")))
    })
}

加入交易相關資訊

transactionInfo 屬性包含的物件提供交易相關財務資料,亦即價格貨幣代碼 (ISO 4217 alpha 格式) 以及價格狀態 (視交易性質而定,可以是「final」或「estimated」,例如:價格可能會因指定的運送地址而異):

private val transactionInfo = JSONObject().apply {
    put("totalPrice", "123.45")
    put("totalPriceStatus", "FINAL")
    put("currencyCode", "USD")
}

加入商家相關資訊

付款要求會採用 merchantInfo 屬性底下,執行該要求的商家相關資訊。在本程式碼研究室,您將著重於其中兩項資訊:

  • merchantId 是指應用程式獲得 Google 核准以正式版運作後,與您帳戶相關聯的 ID。您可以前往 Google Pay 商家主控台,取得隸屬您帳戶的商家 ID。請注意,使用 TEST 環境時,系統不會評估這項資訊。
  • merchantName 是應用程式或機構組織的使用者可見名稱,可以顯示在 Google Pay 付款畫面內,讓使用者瞭解是誰在要求這項操作。

準備好後,請直接將商家相關資訊加入 paymentDataRequest 物件:

private val merchantInfo = JSONObject().apply {
    put("merchantName", "Example Merchant")
    put("merchantId", "01234567890123456789")
}

要求付款資訊並處理結果

現在,將先前定義的設定合併至最終物件,然後傳遞至 loadPaymentData 要求:

private val paymentDataRequestJson = JSONObject(googlePayBaseConfiguration.toString()).apply {
    put("allowedPaymentMethods", JSONArray().put(cardPaymentMethod))
    put("transactionInfo", transactionInfo)
    put("merchantInfo", merchantInfo)
}

這時,您已萬事俱備,可向 Google Pay API 詢問有效的付款方式。要執行此操作,請使用 PaymentsClient 物件中的 loadPaymentData 方法,傳入您剛剛定義的設定:

val paymentDataRequest =
        PaymentDataRequest.fromJson(paymentDataRequestJson.toString())

AutoResolveHelper.resolveTask(
        paymentsClient.loadPaymentData(paymentDataRequest),
        this, LOAD_PAYMENT_DATA_REQUEST_CODE)

呼叫這個方法可觸發顯示 Google Pay 付款畫面的程序。如果沒有任何設定錯誤,您可以看到與目前登入帳戶相關聯的有效付款方式清單。

選取付款方式後,系統會關閉畫面,透過 onActivityResult 方法擷取結果並傳回至您的活動:

public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    when (requestCode) {
        LOAD_PAYMENT_DATA_REQUEST_CODE -> {
            when (resultCode) {
                Activity.RESULT_OK ->
                    PaymentData.getFromIntent(data)?.let(::handlePaymentSuccess)

                Activity.RESULT_CANCELED -> {
                    // The user cancelled without selecting a payment method.
                }

                AutoResolveHelper.RESULT_ERROR -> {
                    AutoResolveHelper.getStatusFromIntent(data)?.let {
                        handleError(it.statusCode)
                    }
                }
            }
        }
    }
}

如果選取成功,可以使用包含所選付款方式相關資訊的 PaymentData 物件取得結果:

{
  "apiVersionMinor": 0,
  "apiVersion": 2,
  "paymentMethodData": {
    "description": "Visa •••• 1234",
    "tokenizationData": {
      "type": "PAYMENT_GATEWAY",
      "token": "examplePaymentMethodToken"
    },
    "type": "CARD",
    "info": {
      "cardNetwork": "VISA",
      "cardDetails": "1234",
      "billingAddress": {
        "phoneNumber": ...,
        ...
      }
    }
  }
}

這項付款方式資訊現在可以用來執行實際交易。

private fun handlePaymentSuccess(paymentData: PaymentData) {
    val paymentMethodToken = paymentData
            .getJSONObject("tokenizationData")
            .getString("token")

    // Sample TODO: Use this token to perform a payment through your payment gateway
}

9. 恭喜!

您已將 Google Pay API 順利整合至自己的應用程式。

要正式發布應用程式前,別忘了先查看整合作業檢查清單。完成檢查清單並經過審查後,您會收到商家 ID (merchantId),用於加進用戶端設定。同樣地,如果您打算使用 (或已經使用) 第三方付款處理方或閘道,請參考 Google Pay 支援的供應商清單並自行完成設定。如要直接整合 Google Pay,請參閱本主題的說明文件部分

涵蓋內容

  • 在應用程式中匯入及設定 Google API。
  • 判斷 API 的支援情形,並據以採取因應措施。
  • 新增按鈕,讓使用者可透過 Google Pay 付款。
  • 載入及處理先前儲存的使用者付款資訊。

後續步驟

  • 如果您尚未在實際應用程式中測試 Google Pay,請立即進行。
  • Google Pay 商家主控台取得商家 ID。
  • 查看整合檢查清單
  • 瞭解兩種不同類型的整合方式,決定哪種方式最適合您的應用程式:直接整合,或者使用支付閘道或處理方。

瞭解詳情

您覺得這實用嗎?

非常實用! 還算符合預期。 不太實用。

您想參考其他程式碼研究室,瞭解其他類型的整合方式 (直接整合、票卡和票證 API) 嗎?

當然,那就再好不過了! 我只需要目前的說明。