일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- mysql
- Koin
- liveData
- Kotlin
- paging
- junit
- databinding
- 인앱결제
- Animation
- RxKotlin
- node
- Android 13
- list
- rx
- node.js
- MediaSession
- PagingLib
- android13
- GCP
- SWIFTUI
- 동영상
- mvvm
- Android
- SwiftUI Tutorial
- 테스트 자동화
- MediaPlayer
- Observable
- google play
- MotionLayout
- Reactive
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
Google Play 결제 시스템 - 앱에 Google Play 결제 라이브러리 통합 본문
이 글에서는 제품 판매를 시작하기 위해 Google Play 결제 라이브러리를 앱에 통합하는 방법을 설명합니다.
이 글에서는 GitHub의 공식 샘플 앱을 기반으로하는 코드 예가 포함되어 있습니다.
참고 사이트: https://developer.android.com/google/play/billing/integrate?hl=ko
구매 진행 과정
일회성 구매 or 정기 결제의 일반적인 구매 흐름은 아래와 같습니다.
- 사용자에게 구입할 수 있는 항목을 보여줍니다.
- 사용자가 구매를 수락할 수 있도록 구매 흐름을 시작합니다.
- 서버에서 구매를 인증합니다.
- 사용자에게 콘텐츠를 제공하고 콘텐츠 전송을 확인합니다. 선택적으로 사용자가 항목을 다시 구입할 수 있도록 항목을 "구매"로 표시합니다.
정기 결제는 취소 될 때까지 자동으로 갱신됩니다. 정기 결제는 다음과 같이 상태가 변하게 됩니다.
- Active: 사용자가 콘텐츠 사용에 문제가 없는 양호한 상태이며 정기 결제에 액세스 할 수 있습니다.
- Cacelled: 사용자가 정기 결제를 취소했지만 만료 시까지 계속 액세스 할 수 있습니다.
- In grace period: 사용자에게 결제 문제가 발생했지만 Google에서 결제 수단을 다시 시도하는 동안 사용자가 계속 액세스 할 수 있습니다.
- On hold: 사용자에게 결제 문제가 발생하여 Google에서 결제 수단을 다시 시도하는 동안 사용자가 더 이상 액세스 할 수 없습니다.
- Paused: 사용자가 액세스를 일시 중지했으며 다시 시작할 때까지 엑세스할 수 없습니다.
- Expired: 사용자가 정기 결제를 취소했으며 정기 결제 액세스 권한을 잃었습니다. 만료 시 사용자가 이탈한 것으로 간주합니다.
구매 토큰 및 주문 ID
Google Play에서는 구매 토큰과 주문 ID를 사용하여 제품 및 거래를 추적합니다.
- 구매토큰은 Google Play에서 제품에 대한 구매자의 자격을 나태내는 문자열 입니다.
- 주문 ID는 Google Play에서 금융 거래를 나타내는 문자열 입니다.
주문 ID는 금융 거래가 발생할 때마다 생성되며 구매 토큰은 사용자가 구매 흐름을 완료할 때만 생성됩니다.
- 1회성 제품의 경우, 매 구매 시 항상 새 구매 토큰이 생성됩니다. 또한 사용자에게 비용이 청구되는 제품인 경우, 새로운 주문 ID도 같이 생성됩니다.
- 정기 결제의 경우 최초 구매 시에는 구매 토큰 및 주문 ID가 생성됩니다. 이후 계속되는 각 결제 기간에 구매 토큰은 동일하게 유지되며 새로운 주문 ID가 발급됩니다.
- 업그레이드, 다운그레이드, 대체 및 재가입은 모두 새로운 구매 토큰 및 주문 ID를 생성합니다.
정기 결제의 경우 다음을 유의해야 합니다.
- 정기 결제 업그레이드, 다운그레이드 및 기타 정기 걸제 구매 흐름은 이전 구매 토큰을 대체해야 하는 구매 토큰을 생성합니다.
- 정기 결제 갱신 주문 번호에는 특정 갱신 인스턴스를 나타내는 정수가 추가로 포함됩니다.
* 참고:
사용자가 인앱상품을 구매할 때 돈을 지불할 필요가 엇는 경우(예: 정기 결제의 무료 체험판 기간에 구매한 경우) $0의 주문 ID가 발급됩니다. 예를 들어 사용자가 정기 결제를 취소하면 결제 기간이 종료될 때까지 정기 결제가 유효한 상태로 유지됩니다.
사용자가 다시 가입하기로 하면 일부 잔액이 계정에 남아 있습니다. 이 경우 새 구매 토큰이 생성되고, $0의 주문 ID가 생성되며, 잔액이 소진된 후 정기 결제가 갱신됩니다.
오류 처리
Google Play 결제 라이브러리는 BillingResult 형식으로 오류를 반환합니다. BillingResult에는 BillingResponseCode가 포함되어 있어 앱에서 발생할 수 있는 결제 관련 오류를 분석합니다. 예를 들어 SERVICE_DISCONNECTED 오류 코드가 수신되면 앱에서 Google Play와의 연결을 다시 초기화해야 합니다. 또한 BillingResult에는 개발 중에 오류를 진단하는 데 유용한 디버그 메시지가 포함되어 있습니다.
- BillingResult: https://developer.android.com/reference/com/android/billingclient/api/BillingResult?hl=ko
- BillingResponseCode: https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode?hl=ko
Google Play에 연결
Google play 결제 시스템과 통합하는 처 번째 단계는 라이브러리를 앱에 추가하고 연결을 초기화 하는 것 입니다.
자세한 내용은 아래에 설명합니다.
Google Play 결제 라이브러리 종속 항목 추가
아래와 같이 앱의 build.gradle 파일에 Google Play 결제 라이브러리 종속항목을 추가합니다.
dependencies {
def billing_version = "3.0.0"
implementation 'com.android.billingclient:billing:$billing_version'. // JAVA
implementation 'com.android.billingclient:billing-ktx:$billing_version'. // KOTLIN
}
BillingClient 초기화
Google Play 결제 라이브러리의 종속 항목을 추가한 후에는 BillingCLient 인스턴스를 초기화해야 합니다.
BillingClient는 Google Play 결제 라이브러리와 나머지 앱 간의 통신을 위한 기본 인터페이스입니다.
BillingClient는 많은 일반적인 결제 작업에 편의 메서드를 제공합니다.
BillingClient를 생성하려면 newBuilder()를 사용해야 합니다. 구매 관련 업데이트를 수신하려면 setListener()를 호출하여
PurchasesUpdateListener에 대한 참조를 전달해야 합니다. 이 리스너는 앱의 모든 구매 관련 업데이트를 수신합니다.
// Kotlin
private val purchaseUpdateListener =
PurchasesUpdatedListener { billingResult, purchases ->
// To be implemented in a later section.
}
private var billingClient = BillingClient.newBuilder(activity)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
Google Play 연결 설정
BillingClient를 만든 후 Google Play에 연결해야 합니다.
Google Play에 연결하려면 startConnection()을 호출합니다. 연결 프로세스는 비동기적입니다.
그리고 클라이언트 설정이 완료되고 추가로 요청할 준비가 되면 BillingClientStateListener를 구현하여 콜백을 수신해야 합니다.
또한 Google Play와 연결이 끊어진 문제를 처리하려면 재시도 로직을 구현해야 합니다.
재시도 로직을 구현하려면 onBindingServiceDisconnected() 콜랩 메서드를 재정의합니다.
그리고 추가 요청을 하기 전에 BillingClient가 startConnection() 메서드를 호출하여 Google Play에 다시 연결하도록 해야 합니다.
아래는 연결을 시작하고 사용준비가 되었는지 테스트하는 예시 입니다.
// Kotlin
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
구입 가능한 제품 표시
Google Play에 연결한 후에는 구매 가능한 제품을 쿼리하여 사용자에게 표시할 준비가 된 것 입니다.
Google Play에 인앱 상품 세부 정보를 쿼리하려면 querySkuDetailsAsync()를 호출합니다.
SKU 세부정보 쿼리는 현지화된 제품 정보를 반환하므로 사용자에게 제품을 표시하기 전에 중요한 단계 입니다.
정기 결제의 경우 제품 디스플레이가 모든 Play 정책을 준수해야 합니다.
querySkuDetailsAsync()를 호출할 때 SkuType과 함께 Google Play Console에서 생성된 제품 ID 문자열 목록을 지정하는 SkuDetailsParams의 인스턴스를 전달합니다.
SkuType은 일회성 제품의 경우 SkuType.INAPP, 정기 결제의 경우 SkuType.SUBS가 될 수 있습니다.
비동기 작업의 결과를 처리하려면 SkuDetailsResponseListener 인터페이스를 구현하는 리스너도 지정해야 합니다.
그런 후 아래와 같이 쿼리가 완료되면 리스너에 알리는 onSkuDetailsResponse()를 제정의할 수 있습니다.
fun querySkuDetails() {
val skuList = ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("gas")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(SkuType.INAPP)
val skuDetailsResult = withContext(Dispatchers.IO) {
billingClient.querySkuDetails(params.build())
}
// Process the result.
}
Google Play 결제 라이브러리는 SkuDetails 객체의 List에 쿼리 결과를 저장합니다.
그런 후 목록의 각 SkuDetails객체에서 다양한 메서드를 호출하여 가격 또는 설명과 같은 인앱 상품에 관한 적절한 정보를 볼 수 있스 ㅂ니다. 사용 가능한 제품 세부 정보를 보려면 SkuDetails 클래스의 메서드 목록을 참조하세요.
판매할 항목을 제공하기 전에 사용자가 그 항목을 이미 소유하고 있지 않은지 확인합니다.
사용자의 항목 라이브러리에 소비성 항목이 여전히 있다면 사용자가 항목을 다시 구입하기 전에 먼저 항목을 구매해야 합니다.
정기 결제를 제공하기 전에 사용자가 이미 정기 결제하지 않았는지 확인합니다.
* 참고: 일부 Android 기기에서는 정기 결제와 같은 특정 상품 유형을 지원하지 않는 버전의 Google Play 스토어 앱이 포함되어 있을 수 있습니다. 앱에서 결제 절차를 시작하기 전에 isFeatureSupported()를 호출하여 판매하려는 제품을 기기에서 지원하는지 확인할 수 있습니다.
지원되는 상품 유형 목록은 BillingClient.FeatureType을 참고하세요.
구매 흐름 시작
앱에서 구매 요청을 시작하려면 앱의 기본 스레드에서 launchBillingFlow() 메서드를 호출합니다.
이 메서드는 querySkuDetailsAsync() 호출에서 얻은 관련 SkuDetails 객체가 포함된 BillingFlowParams 객체를 참조합니다.
BillingFlowParams 객체를 생성하려면 BillingFlowParams.Builder 클래스를 사용합니다.
// An activity reference from which the billing flow will be launched.
val activity : Activity = ...;
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build()
val responseCode = billingClient.launchBillingFlow(activity, flowParams).responseCode
launchBillingFlow() 메서드는 BillingClient.BillingResponseCode에 나열된 몇가지 응답 코드 중 하나를 반환합니다.
이 결과를 검토하여 구매 흐름을 시작하는 동안 발생한 오류가 없는지 확인합니다. OK의 BillingResponseCode는 성공적으로 시작되었음을 나타냅니다. launchBillingFlow() 호출에 성공하면 시스템에서 Google Play 구매 화면을 표시합니다.
아래 그림은 일회성 제품의 구매 화면을 보여줍니다.
Google Play는 onPurchasesUpdate()를 호출하여 PurchasesUpdateListener 인터페이스를 구현하는 리스너에 구매 작업의 결과를 제공합니다. 리스너는 클라이언트를 초기화 할 때 setListener() 메서드를 사용하여 지정됩니다.
가능한 응답. 코드를 처리하려면 onPurchasesUpdated()를 구현해야 합니다. 아래 예는 onPurchasesUpdated()를 재정의하는 방법을 보여줍니다.
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) {
for (purchase in purchases) {
handlePurchase(purchase)
}
} else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
구매 성공 시 아래 그림과 유사한 Google Play 구매 성공 화면이 생성됩니다.
또한 구매 성공 시 사용자가 구매한 인앱 상품의 사용자 및 제품 ID를 나타내는 고유 식별자인 구매 토큰도 생성됩니다.
앱은 구매 토큰을 로컬에 저장할 수 있습니다. 하지만 구매를 인증하고 사기로부터 보호할 수 있는 보안 백엔드 서버로 토큰을 전달하는 것이 좋습니다.
또한 사용자는 주문 ID 또는 거래의 고유 ID가 포함된 거래 영수증을 이메일로 받습니다. 사용자는 일회성 제품 구매 시마다 그리고 최초 정기 결제 구매 및 이후의 반복적인 자동 갱신 시에도 고유 주문 ID가 포함된 이메일을 받습니다. Google Play Console에서 주무 ID를 사용하여 환불을 관리할 수 있습니다.
구매 처리
사용자가 구래를 완료하면 앱에서 구매를 처리해야 합니다. 대부분의 경우 PurchaseseUpdatedListenter()를 통해 구매 알림을 받습니다.
그러나 아래 설명되는 "구매 가져오기" 설명하는 것처럼 앱이 BillingClient.queryPurchaese() 호출을 인식하는 경우가 있습니다.
앱은 다음과 같은 방식으로 구매를 처리해야 합니다.
- 구매를 인증합니다.
- 사용자에게 콘텐츠를 제공하고 콘텐츠 전송을 확인합니다. 선택적으로, 사용자가 항목을 다시 구입할 수 있도록 항목을 소비됨으로 표시합니다.
구매를 인증하려면 먼저 구매 상태가 PURCHASED 인지 확인합니다. 구매가 PENDING이라면 "대기 중인 거래 처리"에 설명된 대로 구매를. 처리해야 합니다.
onPurchasesUpdated() 또는 queryPurchases에서 수신한 구매의 경우 앱이 자격을 부여하기 전에 구매를 추가로 인증하여 정당성을 확인해야 합니다.
구매를 적절하게 인증하는 방법을 알아보려면 "자격을 부여하기 전에 구매 확인"을 참조하세요.
구매를 인증했다면 앱에서 사용자에게 자격을 부여할 준비가 된 것입니다. 자격을 부여한 후 앱에서 구매를 확인해야 합니다.
이 확인은 구매와 관련된 자격을 부여했음을 Google Play에서 알려줍니다.
* 참고: 3일 이내에 구매를 확인하지 않으면 사용자는 자동으로 환불받으며 Google Play는 구매를 취소합니다.
* 참고: 2.0 이전 버번의 Google Play 결제 라이브러리를 사용할 때는 확인이 필요하지 않습니다.
자격을 부여하고 구매를 확인하는 프로세스는 구매가 비소비성인지, 소비성인지 아니면 정기 결제인지에 따라 다릅니다.
소비성인 경우, consumeAsync() 메서드는 확인 요구사항을 충족하며 앱이 사용자에게 자격을 부여했음을 나타냅니다. 또한 이 메서드를 사용하면 앱에서 일회성 제품을 다시 구매할 수 있습니다.
일회성 제품이 소비되었음을 나타내려면 consumeAsync()를 호출하고 Google Play에서 다시 구매할 수 있게 할 구매 토큰을 포함합니다.
또한 ConsumeResponseListener 인터페이스를 구현하는 객체를 전달해야 합니다. 이객체는 소비 작업의 결과를 처리합니다.
작업 완료 시 Google Play 결제 라이브러리가 호출하는 onConsumeResponse() 메서드를 재정의할 수 있습니다.
아래 예는 관련 구매토큰을 사용하여 제품을 소비하는 것을 보여줍니다.
fun handlePurchase(purchase: Purchase) {
// Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
val purchase : Purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant entitlement to the user.
val consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build()
billingClient.consumeAsync(consumeParams, { billingResult, outToken ->
if (billingResult.responseCode == BillingResponseCode.OK) {
// Handle the success of the consume operation.
}
})
}
* 참고: 소비 요청이 때로 실패할 수 있으므로 보안 백엔드 서버를 확인하여 각 구매 토큰이 사용되지 않았는지 확인해야 합니다.
그래야 앱이 동일한 구매에 대해 여러번 자격을 부여하지 않습니다. 또는 자격을 부여하기 전에 앱이 Google Play에서 성공적인 소비 응답을 받을 때까지 기다릴 수 있습니다.
Google Play에서 성공적인 소비 응답을 보낼 때까지 사용자의 구매를 보류하도록 선택하는 경우 소비 요청 이후 구매 추적을 놓치지 않도록 매우 주의해야 합니다.
비소비성 구매를 확인하려면 결제 라이브러리의 BillingClient.acknowledgePurchase() 또는 Google Play Developer API의 Product.Purchases.Acknowledge를 사용합니다.
구매를 확인하기 전에 Google Play 결제 라이브러리의 isAcknowledged() 메서드 또는 Google Developer API의 acknowledgementState 필드를 사용하여 앱에서 이미 구매를 확인했는지 검토해야 합니다.
다음 예는 Google Play 결제 라이브러리를 사용하여 구매를 확인하는 방법을 보여줍니다.
val client: BillingClient = ...
val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ...
fun handlePurchase() {
if (purchase.purchaseState === PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
val ackPurchaseResult = withContext(Dispatchers.IO) {
client.acknowledgePurchase(acknowledgePurchaseParams.build())
}
}
}
}
정기 결제 구매는 비소비성 구매와 유사하게 처리됩니다. Google Play 결제 라이브러리의 BillingClient.acknowledgePurchase() 또는 Google Play Developer API의 Purchases.Subscriptions.Acknowledge를 사용하여 정기 결제를 확인할 수 있습니다.
최초 정기 결제 구매는 모두 확인해야 합니다. 정기 결제 갱신은 호가인하지 않아도 됩니다. 정기 결제를 확인해야 하는 경우에 관한 자세한 내용은 정기 결제 판매 주제를 참고하세요.
구매 가져오기
PurchasesUpdatedListener를 사용하여 구매 업데이트를 수신 대기하는 것만으로는 앱이 모든 구매를 처리하도록 보장하기에 충분하지 않습니다. 앱에서 사용자가 구매한 모든 항목을 인식하지 못할 수 있습니다. 앱에서 구매 추적을 놓치거나 구매를 인식하지 못할 수 있는 몇 가지 시나리오는 다음과 같습니다.
이러한 상황을 처리하려면 앱이 onResume() 및 onCreate() 메서드에서 BillingClient.queryPurchases()를 호출하여 구매 처리에 설명된 대로 모든 구매가 성공적으로 처리되도록 해야 합니다.
앱 외부에서 이루어진 구매 처리
프로모션 사용과 같은 일부 구매는 앱 외부에서 발생할 수 있습니다. 사용자는 앱 외부세어 구매할 때 앱이 올바르게 수신 및 처리되었음을 사용자가 알 수 있도록 앱에서 인앱 메시지를 표시하거나 일종의 알림 메커니즘을 사용하기를 기대합니다.
허용되는 일부 메커니즘은 다음과 같습니다.
- 인앱 팝업을 표시합니다.
- 인앱 메시지 상자에 메시지를 전송하고 인앱 메시지 상자에 새 메시지가 있음을 명확히 알립니다.
- OS 알림 메시지를 사용합니다.
앱에서 구매를 인식할 때 앱이 어떤 상태에 있을 수 있다는 점에 유의하시기 바랍니다.
구매가 이루어졌을 때 앱이 설치되어 있지 않았을 수도 있습니다. 사용자는 앱이 어떤 상태에 있든지 관계 없이 앱을 다시 시작할 때 구매를 수신할 것으로 기대합니다.
구매가 이루어졌을 때 앱이 어떤 상태에 있든지 관계없이 구매를 감지해야 합니다. 하지만 구매 항목이 수신되었음을 사용자에게 즉시 알리지 않아도 되는 몇가지 예외 상황이 있습니다. 예를 들면 아래와 같습니다.
- 게임의 액션 플레이 중에 메시지를 표시하면 사용자의 주의가 산만해질 수 있습니다. 이 경우 액션 플레이가 끝난 후에 사용자에게 알려야 합니다.
- 컷신 중에 메시지를 표시하면 사용자가 산만해질 수 있습니다. 이경우 컷신이 끝난 후에 사용자에게 알려야 합니다.
- 게임의 초기 튜토리얼 및 사용자 설정 중에도 사용자에게 즉실 알리지 않아도 됩니다.
앱 외부에서 이루어진 구매에 관해 사용자에게 아릴는 시기 및 방법을 결정할 때는 항상 사용자를 염두에 두어야 합니다. 알림을 즉시 받지 못하면 언제든 사용자는 혼란스러워하거나 앱 사용을 중지하거나 사용자 지원에 문의하거나 소셜 미디어에 불만들을 게시할 수 있습니다.
대기 중인 거래 처리
* 참고: 대기 중인 거래는 Google Play 2.0 이상에서만 사용할 수 있습니다.
* 참고: 정기 결제 구매에는 추가 결제 방법을 사용할 수 없습니다.
Google Play는 대기 중인 거래 또는 사용자가 구매를 시작한 시점과 구매 결제 수단이 처리되는 시점 사이에 하나 이상의 추가 단계가 필요한 거래를 지원합니다. Google에서 사용자의 결제 수단으로 요금이 청구되었다는 알림을 받을 때까지 앱에서 이러한 유형의 구매에 자격을 부여해서는 안됩니다.
예를 들어 사용자는 결제 방법으로 현금을 선택하여 인앱 상품의 PENDING 구매를 생성할 수 있습니다. 그런 다음, 사용자는 거래를 완료할 오프라인 상점을 선택하고 알림과 이메일을 통해 코드를 수신할 수 있습니다. 사용자는 오프라인 상점에 도착하면 계산원에게 코드를 사용하여 현금으로 결제할 수 있습니다. 그러면 Google은 개발자와 사용자 모두에게 현금이 수령되었음을 알립니다. 다음으로 앱에서 사용자에게 자격을 부여할 수 있습니다.
대기 중인 구매를 사용 설정하려면 앱 초기화의 일부로 enablePendingPurchasese()를 호출하세요.
앱이 PurchasesUpdatedListener를 통해 또는 queryPurchases()를 호출할 결과로 새 구매를 수신할 때 getPurchaseState() 메서드를 사용하여 구매 상태가 PURCHAED 인지 또는 PENDING인지 확인합니다.
상태가 PURCHASED인 경우에만 자격을 부여해야 합ㄴ디ㅏ. 사용자가 구매를 완료할 때 앱이 실행 중이면 PurchasesUpdateListener가 다시 호출되면 PurchaseState는 이제 PURCHASED입니다. 이 시점에서 앱은 "일회성 구매 처리"를 위한 표준 메서드를 사용하여 구매를 처리할 수 있습니다. 또한 앱이 실행되지 않는 동안 PURCHAED 상태로 전환된 구매를 처리하려면 앱의 onResume() 및 onCreate() 메서드에서 queryPurchases()를 호출해야 합니다.
* 참고: 상태가 PURCHASED인 경우에만 구매를 확인해야 합니다. PENDING 상태인 동안에는 확인할 수 없습니다.
또한 앱에서 OneTimeProducsNotifications를 수신대기하여 대기 중인 구매에 "실시간 개발자 알림"을 사용할 수 있습니다.
구매가 PENDING에서 PURCHASED로 전환되면 앱에서 ONE_TIME_PRODUCT_PURCHASED 알림을 수신합니다.
구매가 취소되면 앱에서 ONE_TIME_PRODUCT_CANCELED 알림을 수신합니다. 이 이벤트는 고객이 필수 시간 내에 결제를 완료하지 않은 경우에 발생할 수 있습니다. 이러한 알림 수신시 Purchases.products의 PENDING 상태가 포함된 Google Play Developer API를 사용할 수 있습니다.
* 참고: 대기 중인 거래는 라이선스 테스터를 사용해 테스트 할 수 있습니다. 라이선스 테서터는 2개의 테스트 신용카드 외에도 결제가 몇분 후에 자동으로 완료되거나 취소되는 지연된 결제 방법을 위한 2개의 테스트 도구에 액세스를 할 수 있습니다. 애플리케이션을 테스트하는 동안 이러한 두 도구 중 하나를 사용하여 애플리케이션이 구매 직후에 자격을 부여하거나 구매를 확인하지 않는지 검증해야 합니다. 자동으로 완료되는 테스트 도구를 사용해 구매할 때는 애플리케이션이 구매 완료 후 자격을 부여하고 구매를 확인하는지 검증해야 합니다.
'학습' 카테고리의 다른 글
Google Play 결제 시스템 - 프로모션 코드 (0) | 2020.12.18 |
---|---|
Google Play 결제 시스템 - 정기 결제 판매 (1) | 2020.12.17 |
Google Play 결제 시스템 - 준비하기 (0) | 2020.12.14 |
Google Play 결제 시스템 - 개요 (0) | 2020.12.14 |
MotionLayout - entrance scene sample 분석 (0) | 2020.11.25 |