Google Pay로 Android에서 빠른 결제 환경 구축

1. 소개

Google Pay API는 사용자가 어디서나 Google 계정에 저장된 결제 정보를 사용하여 결제할 수 있도록 지원합니다. 이 Codelab에서는 Google Pay의 Android용 클라이언트 라이브러리를 사용하여, 더 많은 전환을 유도하고 고객 만족도를 높이는 빠르고 편리하고 안전한 환경을 만들어 보며 간단한 샘플 모바일 애플리케이션의 결제 환경을 개선합니다.

Auto T-Shirt Shop은 최신 인공지능 기술을 활용하고 스타일 선호도, 날씨, 연중 시기, 패션 트렌드와 같은 정보를 사용하여 가장 적합한 상품을 추천해 주는 혁신적인 매장입니다.

참여에 관한 측정항목이 이례적으로 높은 수치를 기록하고 있습니다. 이와 동시에 결제 프로세스 도중 유기 수치도 마찬가지로 높습니다. 이 문제를 해결하기로 한 프로젝트 소유자 중 한 명이 Google Pay가 다른 유사 사이트에서 거둔 유망한 결과를 보여주는 동영상을 본 것을 기억합니다. 그래서 통합해 보라고 믿고 사용해 보기로 결정했습니다.

개요

이 Codelab에서는 기존 애플리케이션에 Google Pay를 통합하는 방법을 알아봅니다. 이 과정에서 사용자가 Google Pay에 의해 지원되는 결제 수단을 사용하여 결제할 수 있는지 여부를 확인하는 방법, 결제 버튼의 배치와 디자인, 거래를 실행하는 방법을 알아봅니다.

샘플 애플리케이션

이 Codelab에서는 다음 작업을 수행하는 방법을 알아봅니다.

  1. 기존 Android 애플리케이션에 Google Pay 통합
  2. 사용자가 Google Pay로 결제할 준비가 되었는지 확인
  3. 사용자 인터페이스에 Google Pay 버튼 추가
  4. Google Pay로 결제 작업 완료하기

기본 요건

  • Git
  • Android 스튜디오 또는 Android 애플리케이션용 대체 개발 환경
  • 최신 버전의 Google Play 서비스가 설치된 Android 기기 또는 에뮬레이터

지원

문제가 발생하는 경우 google-pay/android-quickstart GitHub 저장소에서 참조할 수 있는 완전한 솔루션을 확인하세요.

2. 시작하기

GitHub에서 저장소를 클론합니다.

다음 명령어를 사용하여 컴퓨터에 있는 폴더에 저장소를 클론합니다.

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

ZIP 파일을 선호하는 경우:

샘플 애플리케이션 살펴보기

저장소는 간단한 파일 구조로 되어 있습니다. 이 Codelab의 주된 목표는 어떤 프로그래밍 언어, 라이브러리 또는 도구를 사용하든 기존 애플리케이션과 추후 개발할 애플리케이션에 맞게 이 통합을 조정할 수 있는 역량을 제공하는 것입니다.

3. Android 스튜디오에서 프로젝트 열기

복제한 GitHub 저장소에는 기본 활동이 있는 Android 프로젝트가 포함되어 있습니다. 이 단계에서는 이 활동에서 Google Pay 준비 상태를 확인하고 Google Pay 버튼을 표시하도록 수정합니다.

  1. Android 스튜디오 열기
  2. 파일열기를 차례로 선택합니다.
  3. 저장소에서 kotlin 디렉터리를 선택합니다.
  4. 열기를 선택합니다.

build.gradle 파일에 Google Pay 라이브러리를 종속 항목으로 추가

  1. 모듈 수준 Gradle 빌드 파일 (kotlin/app/build.gradle.kts)을 엽니다.
  2. dependencies 섹션에 Google Pay 라이브러리 추가
implementation "com.google.android.gms:play-services-wallet:19.3.0"
  1. 파일을 저장합니다.
  2. File을 선택한 다음 Sync Project with Gradle Files를 선택합니다.

Android 매니페스트 파일에서 Google Pay API 사용 설정

마지막으로 매니페스트 파일의 application 노드 내에 meta-data 요소를 추가합니다.

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

4. 인터페이스에서 Google Pay 버튼을 배치할 위치 결정

뷰의 레이아웃과 전반적인 게재위치는 사용자가 결제 거래를 완료할 가능성에 영향을 미치는 중요한 요소입니다. Google Pay를 사용해 탭 몇 번으로 결제 수단을 선택할 수 있는 기능을 통해 사용자에게 애플리케이션에서 결제 수단을 제공할 위치와 시점에 대한 새로운 옵션을 사용할 수 있게 되었습니다. 예를 들어 프로세스 초기(상품 세부정보 뷰와 같은 영역)에 빠른 결제 옵션을 추가하여 사용자가 좋아하는 단일 상품에 대해 신속하게 결제할 수 있도록 할 수 있습니다.

사용자 인터페이스를 정렬하는 방법을 결정했다면 다음 단계는 Google Pay 버튼을 배치하는 것입니다. 유형, 테마, 모서리 둥글기와 같은 버튼의 시각적 기능을 구성할 수 있습니다. 예를 들면 다음과 같습니다.

Google Pay 동적 버튼 예시

Google Pay 라이브러리에는 사용자 인터페이스에 버튼을 추가하는 과정을 간소화하는 보기가 포함되어 있습니다. XML을 사용하여 레이아웃을 빌드하는 경우 방법은 다음과 같습니다.

<com.google.android.gms.wallet.button.PayButton
    android:id="@+id/googlePayButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

나중에 프로그래매틱 방식으로 버튼을 초기화합니다 ( 참조).
Jetpack Compose를 사용하는 경우 build.gradle 또는 build.gradle.kts 파일에 다음 종속 항목의 최신 버전을 포함합니다.

implementation "com.google.pay.button:compose-pay-button:1.0.0"

그리고 다음과 같이 Compose 레이아웃에 Google Pay 버튼을 추가합니다.

PayButton(
    modifier = Modifier
        .testTag("payButton")
        .fillMaxWidth(),
    onClick = onGooglePayButtonClick,
    allowedPaymentMethods = PaymentsUtil.allowedPaymentMethods.toString()
)

참조: GitHub의 샘플에서 허용되는 결제 수단 목록을 만드는 방법을 자세히 알아보세요.

5. Google Pay API 초기화 및 구성

API 클라이언트 초기화

API를 사용하려면 Google Pay API를 호출하는 데 사용하는 클라이언트 객체를 인스턴스화해야 합니다. 활동 또는 컨트롤러가 생성되면 곧바로 이를 실행할 수 있습니다.

private val paymentsClient: PaymentsClient = createPaymentsClient(context)

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

결제 클라이언트는 WalletOptions 객체로 초기화됩니다. 환경을 ENVIRONMENT_TEST로 설정하면 테스트 결제 정보로 실험할 수 있습니다. 실제 결제 거래를 처리할 준비가 되면 환경 속성을 ENVIRONMENT_PRODUCTION으로 업데이트할 수 있습니다.

Google Pay 요청 분석

Google Pay API에 대한 요청을 실행할 때는 대상 API 버전과 같이 요청에 포함해야 하는 여러 구성 매개변수가 있습니다. 이 Codelab에서는 이 객체에 애플리케이션에서 지원하는 결제 수단에 관한 정보도 포함되어 있습니다. 최종 구조는 다음과 같습니다.

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

속성 allowedPaymentMethods는 결제 수단 목록을 받습니다. 모든 결제 수단에 대해 다음과 같은 속성을 포함해야 합니다.

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

결제 수단 구성

이 예에서는 토큰화된 양식과 기본 계좌 번호 (PAN) 양식 모두에서 Mastercard 및 Visa 카드 결제만 허용합니다. 결제 수단의 코드는 다음과 같습니다.

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

요약 정리

지금까지 살펴본 내용을 정리하겠습니다. 여러분은 애플리케이션에서 지원할 하나의 결제 수단을 정의했고, API 버전 2.0을 사용할 계획입니다. 다음은 그 결과로 도출된 구성의 코드입니다.

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

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

6. Google Pay를 사용하여 결제할 수 있는지 여부 확인

isReadyToPay 요청을 사용하면 애플리케이션의 사용자가 Google Pay로 결제할 수 있는지 확인할 수 있습니다. 이 정보를 사용하여 애플리케이션의 사용자 환경을 적절하게 조정하세요.

이 요청을 수행하려면 Google Pay API의 버전과 애플리케이션에서 허용되는 결제 수단 목록을 지정해야 합니다. 이전 단계에서 정의한 기본 구성 객체는 다음 코드를 포함합니다.

private suspend fun fetchCanUseGooglePay(): Boolean {
    val request = IsReadyToPayRequest.fromJson(googlePayBaseConfiguration.toString())
    return paymentsClient.isReadyToPay(request).await()
}

Google Pay API는 Task를 사용하여 원격 호출을 확인합니다. Tasks API를 사용하면 코루틴을 사용하여 Task 작업을 해결할 수 있습니다. 자세히 알아보기

보시다시피 Google Pay를 통해 결제할 준비가 되었는지 확인하면 불리언 객체가 반환됩니다. 결과가 양수이면 다음 단계는 사용자 인터페이스에 Google Pay 버튼을 표시하는 것입니다. 또는 다른 결제 수단을 지원하는 추가 UI를 표시하는 것이 좋습니다.

Google Pay 버튼 표시

이제 사용자 인터페이스로 돌아가서 이전 통화의 결과에 따라 Google Pay 버튼의 위치를 업데이트합니다. 이 예에서는 클래스를 사용하여 뷰의 상태를 보유합니다. 뷰 상태는 isReadyToPay 호출과 같은 입력을 기반으로 업데이트됩니다.

if (payUiState !is PaymentUiState.NotStarted) {
    PayButton(
        modifier = Modifier
            .testTag("payButton")
            .fillMaxWidth(),
        onClick = onGooglePayButtonClick,
        allowedPaymentMethods = PaymentsUtil.allowedPaymentMethods.toString()
    )
}

7. 실제 결제

### 결제 요청 준비

여러분은 지금까지 Google Pay API를 로드하고 애플리케이션 사용자가 Google Pay를 통해 결제를 진행할 수 있는지 여부를 확인했습니다. 그 결과 UI에 Google Pay 결제 버튼을 표시했고, 이제 사용자가 거래를 시작할 준비가 되었습니다. 이제 사용자가 사용할 수 있는 결제 수단이 포함된 결제 명세서를 로드해 보겠습니다.

isReadyToPay 호출과 마찬가지로 이 요청에는 앞에서 정의한 기본 구성 객체의 속성 (apiVersion, apiVersionMinor, allowedPaymentMethods)이 필요합니다. 이번에는 tokenizationSpecification이라는 새 속성과 거래를 설명하고 청구서 수신 주소, 배송지 주소 또는 사용자 주소 등의 정보를 요청하기 위한 추가 매개변수도 필요합니다. 이메일 주소 또는 전화번호입니다.

#### tokenizationSpecification 속성

토큰화 사양은 사용자가 선택한 결제 수단이 처리되어 거래를 완료하는 데 사용되는 방식을 정합니다.

두 가지 유형의 처리 메커니즘이 지원됩니다. PCI DSS 규격 서버에서 결제 거래를 처리하는 경우에는 DIRECT 사양 유형을 사용하세요. 이 예시에서는 결제 게이트웨이를 사용하여 결제를 처리하므로 PAYMENT_GATEWAY 사양 유형을 설정합니다.

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

parameters 섹션에서 Google Pay API에서 지원하는 제공업체 목록의 게이트웨이와 각 게이트웨이에 필요한 추가 구성을 지정할 수 있습니다. 이 실습에서는 실행된 트랜잭션의 테스트 결과를 반환하는 example 게이트웨이를 사용합니다.

추가 매개변수

마찬가지로 주문을 성공적으로 진행하려면 사용자에게 추가 세부정보를 요청할 수 있습니다. 이 예시에서 billingAddressRequiredbillingAddressParameters 속성을 추가하여 이 거래에서 사용자의 청구서 수신 주소가 전화번호를 포함한 완전한 형식이 필요함을 나타냅니다.

private val cardPaymentMethod = JSONObject()
    .put("type", "CARD")
    .put("tokenizationSpecification", tokenizationSpecification)
    .put("parameters", JSONObject()
        .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 알파 형식)와 함께 가격 상태가 포함된 객체가 포함됩니다. 가격 상태는 거래의 특성에 따라 최종 또는 예상일 수 있습니다 (예: 지정된 배송지 주소에 따라 가격이 달라질 수 있음).

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

#### 비즈니스 정보 추가

결제 요청은 merchantInfo 속성 아래에서 요청을 실행하는 판매자에 관한 정보를 받습니다. 이 Codelab에서는 두 가지 속성에 중점을 둡니다.

  • merchantId에는 계정과 연결된 식별자가 있습니다. 판매자 ID는 결제 및 월렛 콘솔. TEST 환경을 사용할 때는 이 필드가 평가되지 않습니다.
  • merchantName은 사용자에게 표시되는 애플리케이션 또는 조직의 이름입니다. 이는 사용자에게 작업을 요청하는 사람에 대한 추가 컨텍스트를 제공하기 위해 Google Pay 결제 명세서 내에 표시될 수 있습니다.

준비되면 판매자에 관한 정보를 paymentDataRequest 객체에 추가하기만 하면 됩니다.

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

요청 실행 및 결과 처리

이제 구성 객체를 가져와서 loadPaymentData 요청에 전달합니다.

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

이 시점에서는 Google Pay API에 유효한 결제 수단을 요청하는 데 필요한 모든 정보가 확보되었습니다. 이렇게 하려면 PaymentsClient 객체의 loadPaymentData 메서드를 사용하여 방금 정의한 구성을 전달합니다.

fun getLoadPaymentDataTask(): Task<PaymentData> {
    val request = PaymentDataRequest.fromJson(paymentDataRequestJson.toString())
    return paymentsClient.loadPaymentData(request)
}

private fun requestPayment() {
    val task = getLoadPaymentDataTask()
    task.addOnCompleteListener(paymentDataLauncher::launch)
}

Google Pay API는 Activity Result API를 사용하여 결과를 반환합니다. API에는 결과 처리 및 대응을 간소화하기 위한 계약이 포함되어 있습니다. 이 예에서는 결제 결과 외에도 작업에 대한 정보가 포함된 GetPaymentDataResult 계약을 사용합니다.

private val paymentDataLauncher = registerForActivityResult(GetPaymentDataResult()) { taskResult ->
    when (taskResult.status.statusCode) {
        CommonStatusCodes.SUCCESS -> {
            taskResult.result!!.let {
                Log.i("Google Pay result:", it.toJson())
                // TODO something with the result
            }
        }
        CommonStatusCodes.CANCELED -> // The user canceled
        AutoResolveHelper.RESULT_ERROR -> // The API returned an error (it.status: Status)
        CommonStatusCodes.INTERNAL_ERROR -> // Handle other unexpected errors
    }
}

이 메서드를 호출하면 Google Pay 결제 시트의 표시가 트리거됩니다. 구성 오류가 없다면 현재 로그인한 계정에 연결된 유효한 결제 수단 목록을 볼 수 있습니다.

선택하면 시트가 닫히고 결과가 활동으로 다시 전송되고 위에서 정의한 활동 결과 런처에 의해 캡처됩니다.

선택이 완료되면 선택한 결제 수단에 관한 관련 정보가 포함된 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
}

8. 축하합니다.

Android 애플리케이션에 Google Pay를 추가했습니다.

### 다음 단계

### 자세히 알아보기

이 정보가 유익했나요?

<ph type="x-smartling-placeholder"></ph> 매우 유용함 예상했던 대로 잘 모르겠음