인앱결제 결제 자동 취소 이슈 해결
문제
빌링 라이브러리 업데이트 이후 이용자들의 구매가 자동으로 취소가 되고 있는 현상이 발생하였다. 자동으로 취소가 되는 것으로 보니 구매 후 처리가 제대로 되고 있지 않는것 같다.
참고) 구글 플레이 스토어의 정책에 따라, 모든 구매는 구매 후 일정 시간 내에 acknowledge(구독 상품의 경우) 또는 consume(일회성 상품의 경우) 처리가 되어야 합니다. 만약 이 처리가 제대로 이루어지지 않으면, 구글 플레이 스토어는 구매를 자동으로 취소하고 환불할 수 있습니다.
원인
Since v5.0.0 BillingFlowParams.Builder has setProductDetailsParamsList() method which indicates there can be multiple products included within one purchase, so to be consistent with this Purchase has the getProducts() method which returns a list.
Google Play Billing Library v5.0.0부터 BillingFlowParams.Builder에 setProductDetailsParamsList() 메소드가 추가되어 한 번의 결제 흐름에서 여러 상품을 포함할 수 있게 되었습니다. 이 변경으로 인해 Purchase 객체의 getProducts() 메소드는 구매된 상품들의 목록을 반환하는 List<String> 형태로 변경되었습니다.
이러한 업데이트는 단일 구매 내에서 여러 상품을 처리할 수 있도록 하는 등 더 유연한 결제 옵션을 제공하기 위함입니다. 그러나 이 변경은 기존 코드에 영향을 미치며, 특히 getProducts().toString()의 결과가 이전과 다르게 나타나게 만들 수 있습니다.
해결
onPurchasesUpdate 함수에서 product id를 문자열 비교해서 acknowledge(구독 상품의 경우) 또는 consume(일회성 상품의 경우) 처리를 하는 부분이 있는데 getProducts() 메소드가 List<String> 타입을 반환하도록 변경되면서 toString() 메소드를 사용하면 리스트의 내용을 문자열로 변환합니다. 이 경우 리스트에 하나의 요소만 있더라도 결과는 "[element]" 형식으로 반환됩니다.
이 부분에서 조건문에 들어가지 못해서 결재 이후 처리가 제대로 되지 못해서 3일 후에 자동 취소가 된 것이다.
public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
// 결제에 성공한 경우.
if( billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null )
{
Log.d( TAG, "결제에 성공했으며, 아래에 구매한 상품들이 나열될 것 입니다." );
for( Purchase purchase : purchases )
{
Log.d( TAG, "결제에 대해 응답 받은 데이터 :"+ purchase.getOriginalJson() );
String productid = purchase.getProducts().toString();
if(productid.equals("consume")) {
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
//
mBillingClient.consumeAsync(consumeParams, mConsumResListner);
}
else if(productid.equals("sub")) {
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, mSubscribeListner);
}
} else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING){
//거래 중지 등등 ... 결제관련 문제가 발생했을때
Log.d(TAG, "acknowledgePurchase: PENDING");
} else {
//그외 알 수 없는 에러들...
Log.d(TAG, "acknowledgePurchase: UNSPECIFIED_STATE");
}
}
}
}
// 사용자가 결제를 취소한 경우.
else if( billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED )
{
Log.d( TAG, "사용자에 의해 결제가 취소 되었습니다." );
}
// 그 외에 다른 결제 실패 이유.
else
{
Log.d( TAG, "결제가 취소 되었습니다. 종료코드 : " + billingResult.getResponseCode() );
}
}
해결 방법은 간단하다. 그냥 productid.equals("removead")를 productid.contains("removead")로 변경하였더니 정상적으로 처리가 되었다.