미지급된 아이템의 영수증 정보 요청
상품 구매 과정에서 여러 가지 상황으로 인하여 아이템 지급을 실패하거나 취소되는 경우가 발생할 수 있습니다. 이런 상황을 대비하기 위해서는 미지급된 아이템의 영수증 정보를 요청해야 합니다.
IAPV4 클래스의 restore()
메서드를 호출하여 미지급된 아이템의 정보를 요청하세요.
restore()
메서드를 호출한 결과값이SUCCESS
이고 ReceiptList가 전달되었다면, 복구할 아이템이 존재하는 상황입니다. 미지급된 아이템을 지급하고 완료로 처리하세요.restore()
메서드를 호출한 결과 값이SUCCESS
가 아닌 경우에는 게임에서 처리하지 않아도 됩니다.restore()
메서드 호출 후 에러가 발생하더라도 유저가 반드시 알아야 하는 에러가 아니라면 별도 알림 없이 유저가 게임을 계속 플레이할 수 있도록 구현하세요.
다음은 미지급된 아이템의 영수증 정보를 요청하는 예제 코드입니다.
API Reference: hive.IAPV4.restore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 미 지급된 소모성 아이템의 영수증 정보 요청 결과 콜백 핸들러 public void onIAPV4RestoreCB(ResultAPI result, List receiptList) { if (result.isSuccess()) { foreach(hive.IAPV4.IAPV4Receipt receipt in receiptList) { // 전달받은 영수증으로 영수증 검증 요청 } } else if (result.errorCode == ResultAPI.ErrorCode.NOT_OWNED){ // 미지급된 아이템 없음 } else { // Error Handling } } // 미 지급된 소모성 아이템의 영수증 정보 요청 hive.IAPV4.restore(onIAPV4RestoreCB); |
API Reference: IAPV4::restore
1 2 3 4 5 6 7 8 9 10 11 12 |
// 미지급된 소모성 아이템의 영수증 정보 요청 IAPV4::restore([=](ResultAPI const & result, std::vector<std::reference_wrapper<IAPV4Receipt>> receiptList) { if (result.isSuccess()) { for( auto receipt : receiptList) { // 전달받은 영수증으로 영수증 검증 요청 } } else if (result.errorCode == ResultAPI::RESTORE_NOT_OWNED) { // 미지급된 아이템 없음 } else { // Error Handling } }); |
API Reference: com.hive.IAPV4.restore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 미 지급된 소모성 아이템의 영수증 정보 요청 IAPV4.restore(new IAPV4.IAPV4RestoreListener() { @Override public void onIAPV4Restore(ResultAPI result, List<IAPV4.IAPV4Receipt> iapv4ReceiptList) { if (result.isSuccess()) { for (IAPV4.IAPV4Receipt receipt : iapv4ReceiptList) { // 전달받은 영수증으로 영수증 검증 요청 } } else if (result.errorCode == HIVEResultAPITypeRESTORE_NOT_OWNED) { // 미지급된 아이템 없음 } else { // Error Handling } } }); |
API Reference: HIVEIAPV4::restore
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 미지급된 소모성 아이템의 영수증 정보 요청 [HIVEIAPV4 restore:^(HIVEResultAPI *result, NSArray<HIVEIAPV4Receipt *> *receiptList) { // 결과 콜백 if( [result isSuccess] && receiptList != nil && receiptList.count > 0) { for( HIVEIAPV4Receipt* receipt in receiptList) { // 전달받은 영수증으로 영수증 검증 요청 } } else if ([result getErrorCode] == kHIVEResultAPITypeRESTORE_NOT_OWNED) { // 미지급된 아이템 없음 } else { // Error Handling } }]; |
구매 복구 에러코드
에러코드 | 설명 |
NEED_INITIALIZE | 초기화가 안됨 |
NETWORK | 네트워크 에러 |
NOT_SUPPORTED | restore 불가 상태(기기 앱 내 구입 차단 등),지원되지 않는 마켓 설정 시 |
INVALID_SESSION | 복구를 진행할 수 없는 사용자 세션 |
IN_PROGRESS | restore API가 이미 호출됨 |
RESTORE_NOT_OWNED | 복구할 아이템이 없음 |
NOT_OWNED | 복구할 아이템이 없음 |
RESPONSE_FAIL | 기타 오류. Hive IAP 서버 오류 |
구매 영수증 검증 요청
구매 성공 후 게임 서버에서 아이템을 지급하기 전에 Hive IAP의 영수증 검증 API를 이용하여 구매 영수증의 유효성 검증을 구현합니다. 영수증 검증 API 응답값의 hiveiap_transaction_id
는 영수증 별로 고유하게 발급되는 ID이기 때문에 이 값을 게임 서버에 저장 후 영수증의 중복 여부를 체크할 수 있습니다.
Hive IAP 영수증 검증 API를 사용하여 검증하고 요청 파라미터의 모든 값을 전송하면 매출 정보 및 매출에 대한 게임 정보의 애널리틱스 전송을 Hive IAP 서버에서 대행합니다. 또한 Hive Once 통합 조회의 결제 조회를 위한 API를 게임에서 따로 개발할 필요가 없습니다. 자세한 내용은 IAP v4 영수증 검증 가이드를 확인하세요.
구매/복구한 아이템의 지급 완료
상품 구매 후 아이템 지급을 완료했다면 IAPV4 클래스의 transactionFinish()
를 반드시 호출하여 구매를 완료하세요.
다음은 하나의 지급 요청을 완료하는 예제 코드입니다.
API Reference: hive.IAPV4.transactionFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 지급 완료된 아이템의 완료 요청 결과 콜백 핸들러 public void onIAPV4TransactionFinishCB(ResultAPI result, String marketPid) { if (result.isSuccess()) { // 구매 완료 처리 성공 } else { // Error Handling } }; String marketPid = "{YOUR_PRODUCT_MARKET_PID}"; // 지급 완료된 아이템의 완료 요청 hive.IAPV4.transactionFinish(marketPid); |
API Reference: IAPV4::transactionFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
std::string marketPid = "{YOUR_PRODUCT_MARKET_PID}"; // 지급 완료된 아이템의 완료 요청 IAPV4::transactionFinish(marketPid, [=](ResultAPI const & result, std::string marketPid) { // 결과 콜백 if (result.isSuccess()) { // 구매 완료 처리 성공 } else { // TODO : Error Handling } }); |
API Reference: com.hive.IAPV4.transactionFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
String marketPid = "{YOUR_PRODUCT_MARKET_PID}"; // 지급된 아이템의 완료 요청 IAPV4.transactionFinish(marketPid, new IAPV4.IAPV4TransactionFinishListener() { @Override public void onIAPV4TransacionFinish(ResultAPI result, String marketPid) { if (result.isSuccess()) { // 구매 완료 처리 성공 } else { // Error Handling } } }); |
API Reference: HIVEIAPV4::transactionFinish:handler:
1 2 3 4 5 6 7 8 9 10 11 12 |
NSString* marketPid = @"{YOUR_PRODUCT_MARKET_PID}"; // 지급 완료된 아이템의 완료 요청 [HIVEIAPV4 transactionFinish:marketPid handler:^(HIVEResultAPI *result, NSString *marketPid) { if ([result isSuccess]) { // 구매 완료 처리 성공 } else { // Error Handling } }]; |
다음은 여러 개의 지급 요청을 완료하는 예제 코드입니다.
API Reference: hive.IAPV4.transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 지급 완료된 아이템들의 완료 요청 결과 콜백 핸들러 public void onIAPV4TransactionMultiFinishCB(List resultList, List marketPidList) { hive.Logger.log("IAPTestView.onIAPV4TransactionMultiFinishCB() CallbacknresultList = " + resultList + "nmarketPidList : " + marketPidList); }; List marketPidList = new List(); marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_01}"); marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_02}"); // 지급 완료된 아이템의 완료 요청 hive.IAPV4.transactionMultiFinish(marketPidList); |
API Reference: IAPV4::transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
std::vector<std::string> marketPidList; marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_01}"); marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_02}"); marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_03}"); // Hive IAP v4 의 지급 완료된 복수의 아이템들의 트랙잭션 종료 요청 IAPV4::transactionMultiFinish(marketPidList, [=](std::vector<ResultAPI> const & resultList,std::vector<std::string> const & marketPidList) { // 결과 콜백 for(ResultAPI result : resultList) { if (result.isSuccess()) { // 아이템 트랜잭션 종료 성공 } else { // TODO : Error Handling } } }); |
API Reference: com.hive.IAPV4.transactionMultiFinish
1 2 3 4 5 6 7 8 9 |
// 복수의 지급된 아이템의 완료 요청 IAPV4.transactionMultiFinish(marketPidList, new IAPV4.IAPV4TransactionMultiFinishListener() { @Override public void onIAPV4TransacionMultiFinish(List<ResultAPI> resultList, List<String> marketPidList) { for (int i = 0; i < resultList.size(); i++) { // Logger.log("transactionFinish : " + resultList.get(i)); } } }); |
API Reference: HIVEIAPV4::transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
NSMutableArray<NSString*> *maketPidList = [NSMutableArray array]; [maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_01}"]; [maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_02}"]; [maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_03}"]; // Hive IAP v4 의 지급 완료된 복수의 아이템들의 트랙잭션 종료 요청 [HIVEIAPV4 transactionMultiFinish:maketPidList handler:^(NSArray<HIVEResultAPI *> *resultList, NSArray<NSString *> *marketPidList) { // 결과 콜백 for(HIVEResultAPI* result in resultList) { if ([result isSuccess]) { // 아이템 트랜잭션 종료 성공 } else { // TODO : Error Handling } } }]; |
유저 구매 활동 정보 얻기: AccountUuid
를 활용
하나의 게임 계정이 여러 앱 스토어 계정을 동원해 결제하는 등 결제 시스템을 악용하는 사용자가 존재할 수 있습니다. 게임 스튜디오 측에서는 결제 사용자 정보(AccountUuid)를 대조하는 방법으로 특정 사용자 행태를 얻어 분석할 수 있습니다.
아래 메서드는 Hive SDK가 앱 스토어에 전달하는 UUID v3 형태의 PlayerId 해시값인 AccountUuid
를 반환합니다.
1 2 |
// 현재 PlayerId의 uuid string String accountUuid = hive.IAPV4.getAccountUuid(); |
1 2 |
// 현재 PlayerId의 uuid string string accountUuid = IAPV4::getAccountUuid(); |
1 2 |
// 현재 PlayerId의 uuid string String accountUuid = IAPV4.getAccountUuid() |
1 2 |
// 현재 PlayerId의 uuid string val accountUuid: String? = IAPV4.getAccountUuid() |
1 2 |
// 현재 PlayerId의 uuid string NSString *accountUuid = [HIVEIAPV4 getAccountUuid]; |
1 2 |
// 현재 PlayerId의 uuid string let accountUuid = IAPV4Interface.getAccountUuid() |
게임 스튜디오가 이 해시값과 구매 영수증 정보를 함께 사용하면 어떤 사용자의 상품 구매가 정상적이었는지 분석할 수 있습니다. 아래는 AccountUuid
를 활용해 특정 PlayerId를 가진 게임 계정 내에 여러 게임 캐릭터가 있을 때, 이 게임 계정의 구매 활동을 분석하는 예시입니다. 이 예시는 개발 참고용이며 실제 동작을 보장하지 않습니다.
구매 메타 정보를 게임 서버에 미리 저장
구매 요청이 일어나기 전에 구매 메타 정보(AccountUuid
와 케릭터 정보 등)을 게임 서버에 저장합니다.
1 2 3 4 5 6 7 8 9 10 |
/* 구매 전 게임 클라이언트가 게임 서버에 전달하는 로직 * * @param purchaseTime: 구매 시간. 영수증들은 보통 UTC 기준입니다. since the epoch (Jan 1, 1970). * @param productId: 구매 상품 ID. * @param accountUuId: PlayerId 해시값. 영수증에 포함되며 IAPV4.getAccountUuid()로 얻을 수 있습니다. * @param characterId: PlayerId 내의 케릭터 식별자 입니다. */ game.sendPurchaseGameData(purchaseTime, productId, accountUuid, characterId) |
bypassInfo
전달
구매 요청이 일어나면 bypassInfo
데이터를 게임 서버에 전달합니다. 아래 코드는 개발 참고용 의사 코드입니다.
1 2 3 4 5 |
IAPV4.purchase(productId) { iapv4Receipt -> game.sendReceipt(iapv4Receipt.purchase_bypass_info) } |
영수증 검증 요청
게임 서버는 bypassInfo
데이터를 Hive IAP v4 서버에 전달하고 영수증 검증을 요청합니다. 영수증 검증 요청은 다음을 확인하세요.
AccountUuid
는 응답 값에 있는 앱 마켓/스토어 영수증 원문인 hiveiap_receipt
안에 다음과 같이 포함되어 있습니다.
1 2 3 4 5 6 |
# Apple # 구매 시간: purchase_date_ms # 구매 상품: product_id # AccountUuid: app_account_token |
1 2 3 4 5 6 |
# Google # 구매 시간: purchaseTime # 구매 상품: productId # AccountUuid: obfuscatedAccountId |
구매 메타 정보의 AccountUuid
와 hiveiap_receipt
의 AccountUuid
를 대조해 분석
앞서 구매 메타 정보에 저장해두었던 AccountUuid
와 영수증 검증 응답 값에서 얻은 AccountUuid
를 대조해 게임 캐릭터 정보 등 분석에 필요한 유저 정보를 찾습니다. 구매 메타 정보와 영수증 정보를 매치시켜 해당 게임 계정의 구매 활동을 분석할 수 있습니다.
한 유저가 여러 아이템을 구매한 경우, 구매 메타 정보와 hiveiap_receipt
의 purchaseTime
을 대조하여 각 구매 건을 특정할 수 있습니다. hiveiap_receipt
에 관한 자세한 내용은 영수증 검증에서 마켓별 API 응답값을 확인하세요.
유저 구매 활동 정보 얻기: iapPayload
를 활용
Purchase()로 구매를 요청할 때 iapPayload
에 게임사에서 사전에 정의한 구매 활동 분석용 데이터를 넣으면, Hive 서버가 iapPayload
에 해당하는 구매 영수증을 매치시켜 게임 서버에 전달합니다. 게임 스튜디오는, 영수증에 있는 정보와 iadPayload
에 있는 정보를 함께 사용하여 사용자 구매 활동을 분석할 수 있습니다.
iapPayload
를 정의해 Purchase()
실행
각 상품 구매 요청을 실행할 때 iapPayload
에 원하는 필드와 값을 정의하여 인자로 사용합니다. 이 과정은 구매 메타 데이터 정의와 유사합니다.
영수증 검증 요청하여 iapPayload
와 이에 해당하는 영수증을 수령
결제가 완료되고 영수증 검증 요청을 할 때, Hive 서버는 게임 서버에 구매 건별로 iapPayload
와 이에 해당하는 영수증을 매치시켜 전달합니다. 게임 스튜디오는 iapPayload
영수증에 있는 정보를 활용해 유저의 구매 활동을 분석할 수 있습니다.