콘텐츠로 이동

상품 목록 조회와 구매

상품 목록 조회

게임 내 상점 진입 시 상품 목록 조회 API를 호출해야 합니다. 상품 목록 요청을 수행하면 결과 통지 시 IAPV4Product 클래스에 상품 목록 정보를 포함하여 반환합니다.

상품 정보 정의

필드명 설명
marketPid 마켓에 등록된 고유 상품 ID
currency 통화 코드 (예. KRW / USD)
price 상품 가격
title 상품의 타이틀
displayPrice 상품 가격 문자열 (예. $100.00) 자세히
productDescription 상품 설명
originalMarketJson 마켓에서 받은 상품 정보 원문 Google 구독 V2 사용 시 Google Play Console에 정의한 제품 정보를 확인할 수 있음
displayOriginalPrice 할인 전 가격 문자열
originalPrice 할인 전 가격
iconURL 상품 아이콘 (512*512) Google 전용이며 Hive SDK v4.12.0 이후부터 사용 가능

displayPrice

  • 통화 기호와 가격을 조합한 형태(예: $0.99)로 displayPrice를 전달합니다. Android와 iOS의 노출 방식이 다르기 때문에 일부 국가에서는 OS에 따라 통화 기호와 가격 순서가 다를 수 있습니다.
  • 각 나라의 통화기호는 통화기호표와 동일하게 출력합니다. 통화기호는Hive 식별자 정책을 참고하세요.
  • 다른 나라에서 부가세를 추가하거나 변동하는 경우에 서버에서 계산하여 displayPrice, price, displayOriginalPrice, originalPrice에 반영하므로 추가 작업이 필요 없습니다.
Note

Google은 price 값과 originalPrice 값이 다르면 할인 전 원가를 표기할 수 있습니다. 두 값이 같다면 할인 상태가 아님을 의미합니다.

Apple에서는 iconURL 값을 제공하지 않습니다. originalPrice, displayOriginalPrice는 Google(v4 12.0.0 +), Apple(v4 24.0.0 +) 전용이며, price 값과 originalPrice 값이 같다면 할인 상태가 아님을 의미합니다. 반대로 두 값이 다르다면 할인 중이므로 할인가와 원가를 따로 표기하는 등의 활용이 가능합니다.

상품 목록을 조회하려면 IAPV4 클래스의 getProductInfo() 메서드를 호출하고 결과값으로 상품 목록의 상품 정보, 러비 잔액을 전달 받습니다.

다음은 상품 목록 조회를 요청하는 예제 코드입니다.

API Reference: hive .IAPV4.getProductInfo

using hive;    
    IAPV4.getProductInfo((ResultAPI result, List<IAPV4Product> productInfoList, int balance) => {    
         if (result.isSuccess()) {    
            // call successful    
        }    
});
#include "HiveIAPV4.h"

FHiveIAPV4::GetProductInfo(FHiveIAPV4OnProductInfoDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TArray<FHiveIAPV4Product>& ProductInfoList, uint32 Balance) {
        if (Result.IsSuccess()) {
                // API 호출 성공
        }
}));

API Reference: IAPV4 ::getProductInfo

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;    
    using namespace hive;    
    IAPV4::getProductInfo([=](ResultAPI const & result, vector<IAPV4Product> const & productInfoList, unsigned int balance) {    
         if (result.isSuccess()) {    
         // call successful    
         }    
});

API Reference: IAPV4.getProductInfo

import com.hive.IAPV4    
    import com.hive.ResultAPI    
    IAPV4.getProductInfo(object : IAPV4.IAPV4ProductInfoListener {    
         override fun onIAPV4ProductInfo(result: ResultAPI, iapV4ProductList: ArrayList<IAPV4.IAPV4Product>?, balance: Int) {    
             if (result.isSuccess) {    
                 // call successful    
             }    
         }    
})

API Reference: com .hive.IAPV4.getProductInfo

import com.hive.IAPV4    
    import com.hive.ResultAPI    
    IAPV4.INSTANCE.getProductInfo((result, iapV4ProductList, balance) -> {    
         if (result.isSuccess()) {    
             // call successful    
         }    
});

API Reference: IAPV4Interface .getProductInfo

import HIVEService    
    IAPV4Interface.getProductInfo() { result, productInfoList, balance in    
        if result.isSuccess() {    
            // call successful    
        }    
}

API Reference: HIVEIAPV4::getProductInfo

#import <HIVEService/HIVEService-Swift.h>    
    [HIVEIAPV4 getProductInfo: ^(HIVEResultAPI *result, NSArray<HIVEIAPV4Product *> *productInfoList, NSUInteger balance) {    
         if ([result isSuccess]) {    
            // call successful    
         }    
}];
Warning

getProductInfo() 메서드 호출 실패 시 상품 페이지 구현을 위한 소모성 아이템 정보 활용이 어렵습니다. 실패 Result API 코드를 받았다면, 게임 클라이언트에서 성공 콜백을 받을 때까지 재시도하거나 에러 상황(마켓 사용 불가)을 팝업으로 사용자에게 노출하는 등을 자체적으로 구현하여 대응해야 합니다. IAP v4 Result API 코드 가이드에서 관련 Result API 코드를 확인하세요.

Note

Google Play용 Windows 앱(Hive SDK v4 Unity Windows 23.0.0 이상)에서 GOOGLE_PLAYSTORE 마켓을 사용할 때, IAPV4.getProductInfo가 처음으로 호출되면 마켓에서 상품을 결제할 계정을 선택하는 Google 계정 로그인 화면이 앱 사용자에게 나타납니다. 이 로그인 과정은 앱 개발사가 구현하는 기능이 아니며, Hive SDK에서 자동으로 수행합니다.
결제용 Google 계정의 인증 정보가 만료되면, Hive SDK는 자동으로 재인증 과정을 실행합니다.

상품 구매

Hive IAP v4에서 상품 구매는 App Store, Play Store에 등록된 marketPid를 매개변수로 IAPV4 클래스의 purchase() 메서드를 호출하여 요청합니다.

다음은 상품 구매를 요청하는 예제 코드입니다.

API Reference: hive .IAPV4.purchase

using hive;    
    String marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    String iapPayload = "{YOUR_CUSTOM_PAYLOAD}"    

    IAPV4.purchase(marketPid, iapPayload, (ResultAPI result, IAPV4Receipt receipt) => {    
    if (result.isSuccess()) {    
             // TODO: Request verification of receipt with received receipt    
         }    
});
#include "HiveIAPV4.h"

FString MarketPid = TEXT("YOUR_PRODUCT_MARKET_PID");
FString IapPayload = TEXT("YOUR_CUSTOM_PAYLOAD");

FHiveIAPV4::Purchase(MarketPid, IapPayload, FHiveIAPV4OnPurchaseDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHiveIAPV4Receipt& Receipt) {
        if (Result.IsSuccess()) {
                // API 호출 성공
        }
}));

API Reference: IAPV4 ::purchase

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;    
    using namespace hive;    
    string marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    string iapPayload = "{YOUR_CUSTOM_PAYLOAD}";    
    IAPV4::purchase(marketPid, iapPayload, [=](ResultAPI const & result, IAPV4Receipt const & receipt) {    
         if (result.isSuccess()) {    
             // TODO: Request verification of receipt with received receipt    
         }    
});

API Reference: com.hive.IAPV4.purchase

import com.hive.IAPV4    
    import com.hive.ResultAPI    
    val marketPid = "{YOUR_PRODUCT_MARKET_PID}"    
    val iapPayload = "{YOUR_CUSTOM_PAYLOAD}"    
    IAPV4.purchase(marketPid, iapPayload, object : IAPV4.IAPV4PurchaseListener {    
         override fun onIAPV4Purchase(result: ResultAPI, iapV4Receipt: IAPV4.IAPV4Receipt?) {    
             if (result.isSuccess) {    
                 // call successful    
             }    
         }    
})

API Reference: com .hive.IAPV4.purchase

import com.hive.IAPV4;    
    import com.hive.ResultAPI;    
    String marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    String iapPayload = "{YOUR_CUSTOM_PAYLOAD}";    
    IAPV4.INSTANCE.purchase(marketPid, iapPayload, (result, iapV4Receipt) -> {    
         if (result.isSuccess()) {    
             // call successful    
         }    
});

API Reference: HIVEIAPV4::purchase:additionalInfo:handler:

import HIVEService    
    let marketPid = "{YOUR_PRODUCT_MARKET_PID}"    
    let iapPayload = "{YOUR_CUSTOM_PAYLOAD}"    

    HIVEIAPV4.purchase(marketPid, iapPayload: iapPayload) { result, receipt in    
         if result.isSuccess() {    
             // TODO: Request verification of receipt with received receipt    
         }    
}

API Reference: HIVEIAPV4::purchase:additionalInfo:handler:

#import <HIVEService/HIVEService-Swift.h>

NSString *marketPid = @"{YOUR_PRODUCT_MARKET_PID}";
NSString *iapPayload = @"{YOUR_CUSTOM_PAYLOAD}";

[HIVEIAPV4 purchase: marketPid iapPayload: iapPayload handler: ^(HIVEResultAPI *result, HIVEIAPV4Receipt *receipt) {
    if ([result isSuccess]) {
        // TODO: Request verification of receipt with received receipt
    }
}];
Note

운영체제/마켓별로 지원하는 기능에 차이가 있을 수 있습니다. 자세한 내용은 기능 지원 현황을 확인하세요.

iapPayload 활용

구매(purchase()) 또는 구독(purchaseSubscription) 메서드를 실행할 때, 게임사는 iapPayload를 인자로 넘길 수 있습니다. iapPayload는 게임사에서 자체 정의한 구매 메타데이터입니다. 예를 들면, 어떤 유저가 상품을 구매했을 때 구매 시간, 상품을 구매한 유저 정보, 구매한 게임 캐릭터 정보, 구매 수량(소모성 아이템), 구매 토큰 등일 수 있습니다.

iapPayload를 인자로 넘기면 Hive IAP 서버가 구매 영수증을 검증할 때 이 iapPayload값이 어떤 구매 영수증에 해당하는 값인지 매칭하여 게임 서버에 알려줍니다. 정확히는, iapPayload값과 영수증 고유 키에 해당하는 hiveiap_transaction_id값을 매칭하여 게임 서버에 전달합니다.

구매 영수증과 iapPayload 짝을 활용하면 다양한 문제를 해결할 수 있습니다. 예를 들어, 유저가 아이템 구매 시 에러가 발생해 결제는 끝났지만 아이템을 지급하지 못한 상황이 있을 수 있습니다. 이 때, restore() 메서드를 실행하면 유저가 아이템을 구매한 영수증을 얻을 수는 있지만, 이 영수증에는 유저에게 지급해줘야할 아이템이 어떤 종류의 아이템인지, 몇 시에 구매한 아이템인지, 어떤 캐릭터가 구매한 아이템인지 정보는 존재하지 않기 때문에 어떤 아이템을 유저에게 지급해야 하는지 알 수가 없습니다. 하지만, 구매 영수증과 짝지어진 iapPayload를 통해 이 정보들을 알 수 있어 유저에게 아이템을 지급할 수 있습니다.

Note

iapPayload를 활용하면 결제 시스템을 악용하는 유저 정보 분석이 가능합니다.

iapPayload는 UTF-8 기준 최대 20KB 용량을 가질 수 있습니다. 운영체제/마켓별로 지원하는 기능에 차이가 있을 수 있습니다. 자세한 내용은 기능 지원 현황을 확인하세요.

Warning

iapPayload를 전달할 때에는 암호화하여 전달하기를 권장합니다. iapPayload는 영수증과는 달리 위, 변조에 취약합니다.

소모성 아이템 구매 수량 설정

Google Play Store에서는 유저가 장바구니에서 수량을 지정해 한 번의 거래로 같은 인앱 상품을 두 개 이상 구매할 수 있습니다. Google Play Console 상품 설정에서 다중 수량 구매를 허용하면 앱은 다중 수량 구매를 처리하고 지정한 구매 수량에 따라 아이템을 지급해야 합니다. 단, 다중 수량 구매는 소비 후 다시 구매할 수 있는 상품인 소모성 인앱 상품을 위한 것입니다. 반복적으로 구매할 수 없는 상품에는 이 기능을 사용하도록 설정하지 마세요.

Note

어떤 아이템에 대해 다중 수량 구매를 적용하면, 영수증 검증 응답 hiveiap_quantity에서 구매 수량을 확인 할 수 있습니다.

purchase() 메서드 호출 시 주의사항

  • purchase() 메서드를 호출하는 도중 마켓 오류로 RESPONSE_FAIL, CANCELED 에러가 발생하면 사용자에게 구매 과정에 문제가 있음을 알립니다.
  • 구매 과정에 문제가 있다는 알림을 사용자가 확인했다면 restore() 메서드를 호출하여 구매 복구를 진행합니다.
  • purchase() 메서드를 호출하는 도중 NEED_RESTORE 에러가 발생하면 구매가 취소되며, 이 경우 restore()메서드를 호출하여 구매 복구를 진행합니다.
  • purchase() 메서드를 호출하는 도중 오프라인 결제를 시도하는 경우 또는 미성년자 가족 구성원이 부모에게 아이템 결제를 요청하는 경우 ITEM_PENDING 에러가 발생하며 해당 아이템은 구매 대기 상태가 됩니다. 부모가 미성년 가족을 대신해 구매하는 기능은 현재 Google Play Store, Amazon 마켓, Apple App Store만 지원합니다.
  • 오프라인 결제 성공한 경우 또는 부모가 미성년자 가족 구성원에게 요청받은 아이템 결제를 승인하는 경우 UserEngagement를 통해 `IAP_UPDATED` 이벤트를 수신합니다. UserEngagement eventEnd 콜백으로 파라미터를 전달받을 때 `type`이 "subscription"이면 `restoreSubscription()`, `type`이 비어있는 경우 `restore()` 메서드를 호출하세요. 결제 완료 상품의 영수증 정보를 확인할 수 있습니다.
  • 인앱 구입 차단 문구 가이드를 참고하면 필요에 따라 NOT_SUPPORTED 에러 처리로 사용자가 구매 할 수 없는 상태임을 알릴 수 있습니다.
  • 데스크톱 환경에서 HIVESTORE로 구매하는 경우에는 새 창에서 결제 요청 화면이 노출됩니다. `hive.IAPV4.purchase(marketPid, null, onIAPV4PurchaseCB);`를 호출하면 영수증 정보 없이 `onIAPV4PurchaseCB`를 통해 ErrorCode:IAPSUCCESS=90Code:IAPV4HiveStoreSuccess=-6110000의 응답을 즉시 반환하며, ErrorCode(또는 Code)를 판별하여 아이템 지급 가능 상태에 대한 안내 메시지를 노출할 수 있습니다.
  • Google Play용 Windows 앱(Hive SDK v4 Unity Windows 23.0.0 이상)에서 `GOOGLE_PLAYSTORE` 마켓을 사용할 때, 결제용 Google 계정의 인증 정보가 만료되면, Hive SDK는 자동으로 재인증 과정을 실행합니다.
  • Google Play용 Windows 앱(Hive SDK v4 Unity Windows 23.0.0 이상)에서 `GOOGLE_PLAYSTORE` 마켓을 사용할 때, 사용자가 앱상에 나타난 결제 대기 팝업의 확인 버튼을 눌렀을 때, 결제 완료 여부가 확인되지 않은 경우 `onIAPV4PurchaseCB`로 `ErrorCode:IAPSUCCESS=90`과 `Code:IAPV4PendingPurchase=-6100013` 응답을 반환합니다. 이 응답은 결제에 실패한 상황이 아니며, 사용자가 돈을 지불했지만 내부 오류로 결제 완료가 확인되지 않았거나, 사용자가 결제를 하지 않은 경우에 해당합니다. 이 경우 영수증을 반환하지 않으며, 사용자가 결제 브라우저 창에서 결제를 완료했다면 `IAPV4.restore`로 영수증을 얻을 수 있습니다.

구매 에러코드

에러코드 설명
NEED_INITIALIZE 초기화 진행 필요
NETWORK 네트워크 에러
NOT_SUPPORTED 구매 불가 상태(기기 앱 내 구입 차단 등), 지원되지 않는 마켓 설정 시
INVALID_SESSION 구매를 진행할 수 없는 사용자 세션
INVALID_PARAM 파라미터 오류
IN_PROGRESS purchase API가 이미 호출됨
ITEM_PENDING 오프라인 결제를 시도하거나 가족 구성원인 미성년자 사용자가 부모에게 결제 요청을 한 경우
CANCELED 사용자에 의한 취소
NEED_RESTORE restore API 호출 필요
RESPONSE_FAIL 기타 오류. Hive IAP 서버 오류

인앱 구매 차단 문구

한글 앱 내 구입 기능이 차단이 되어 구매가 불가합니다. 해제 후 다시 시도해 주세요. (설정 > 스크린 타임 > 콘텐츠 및 개인 정보 보호 제한 > iTunes 및 App Store 구입 > 앱 내 구입)
영문 You can't make a purchase because the in-app purchase feature has been blocked. Please unblock the feature and try again. (Settings > Screen Time > Content & Privacy Restrictions > iTunes & App Store Purchases > In-app Purchases)
프랑스어 u ne peux pas effectuer l'achat car la fonction d'achat in-app a été bloquée. Débloque d'abord la fonction et essaie de nouveau. (Réglages > Temps d’écran > Restrictions relatives au contenu et à la confidentialité > Achats dans l’iTunes et l’App Store > Achats intégrés)
독일어 Kauf nicht möglich, weil das In-App-Kauf-Feature gesperrt ist. Bitte entsperre es und versuche es erneut. (Einstellungen > Bildschirmzeit > Beschränkungen > Käufe im iTunes & App Store > In-App-Käufe)
일본어 App内の購入機能が制限されており、購入できません。 解除した後、再度お試しください。 (設定 > スクリーンタイム > コンテンツとプライバシーの制限 > iTunesおよびApp Storeでの購入 > App内課金)
중국어(간체) 因App内购功能已关闭,无法进行购买。 请开启后再试。 (设置 > 屏幕使用时间 > 内容和隐私访问限制 > iTunes Store 与 App Store 购买项目 > App 内购买项目)
중국어(번체) 因App內購功能已關閉, 無法進行購買. 請開啟後重新再試 (設定 > 螢幕使用時間 > 內容與隱私權限制 > iTunes 與 App Store 購買 > App 內購買)
러시아어 Покупка недоступна, т.к. на устройстве отключены встроенные покупки. Активируйте данную функцию и повторите попытку. (Настройки > Экранное время > Контент и конфиденциальность > Покупки в iTunes Store и App Store > Встроенные покупки)
스페인어 No se puede realizar la compra porque la función de Compras en la app ha sido bloqueada. Favor de desbloquear la función y volver a intentar. (Ajustes > Tiempo de uso > Restricciones de contenido y privacidad > Compras en iTunes y App Store > Compras dentro de la app)
포르투갈어 Você não pode efetuar uma compra porque a função de compra do app foi bloqueada. Por favor, desbloqueie a função e tente novamente. (Definições > Tempo de ecrã > Conteúdo e privacidade > Compras na iTunes e App Store > Compras integradas)
인도네시아어 Pembelian tidak bisa dilakukan karena fitur pembelian In-App telah dibatasi. Silakan matikan pembatasan dan coba lagi. (Pengaturan > Durasi Layar > Pembatasan Konten & Privasi > Pembelian iTunes & App Store > Pembelian In-app)
터키어 Uygulama içi satın alma özelliği bloke edildiği için satın almayı yapamazsınız. Lütfen özelliğin blokajını kaldırıp tekrar deneyiniz. (Ayarlar > Ekran Süresi > İçerik ve Gizlilik Sınırlamaları > iTunes ve App Store Satın Alımları > Uygulama İçi Satın Alım)
베트남어 Bạn không thể thực hiện giao dịch do tính năng Mua In-App đang bị tắt. Vui lòng bật tính năng và thử lại. (Cài đặt > Thời gian sử dụng > Bật giới hạn > Mua hàng iTunes & App Store > Mua In-app)
태국어 คุณไม่สามารถซื้อได้เนื่องจากเมนูการซื้อของในแอพพลิเคชั่นถูกบล็อคอยู่ กรุณาปลดล็อคแล้วลองอีกครั้ง (การตั้งค่า > เวลาหน้าจอ > จำกัดเนื้อหาและความเป็นส่วนตัว > สินค้าที่ซื้อใน iTunes & App Store > การซื้อภายในแอพ)
이탈리아어 Non puoi effettuare l'acquisto perché la funzione di acquisti in-app è bloccata. Preghiamo di sbloccare la funzione e riprovare. (Impostazioni > Tempo di utilizzo > Contenuti e privacy > Acquisti su iTunes e App Store > Acquisti in-app)
아랍어 .لا يمكنك إجراء عملية شراء لأن ميزة الشراء داخل التطبيق قد تم حظرها .الرجاء إلغاء حظر الميزة والمحاولة مرة أخرى (الإعدادات > مدة استخدام الجهاز > قيود المحتوى والخصوصية > الشراء من iTunes Store و App Store > الشراء من داخل التطبيق)

청약 철회 규정

콘텐츠산업 진흥법에 따라 게임 상점에 청약 철회에 대한 안내문과 청약 철회 규정 안내 링크를 제공하세요. iOS의 경우 Apple 검수 과정에서 청약 철회 안내 문구가 노출되면 게임 앱 심사 거절 사유가 될 수 있습니다.