Steam 미지급 구매 복구
결제는 끝났지만 상품 지급이 마무리되지 않은 Steam 구매를 조회해 남은 상품 지급과 거래 종료를 완료합니다.
Steam 결제 구현의 설정과 설치를 먼저 완료하세요.
실행 시점
아래 상황에서 구매가 끝나지 않은 채 남습니다.
- 영수증 검증 직후 앱이 종료되었거나 네트워크가 끊긴 경우
- 검증에는 성공했지만 상품 지급이나 구매 완료 처리가 실패한 경우
Steam 구매는 미지급 구매 목록을 Hive Axyl 서버가 보관합니다. 앱을 실행할 때와 상점 화면을 열 때 복구를 실행하세요. 두 시점이 겹치더라도 복구가 동시에 두 번 실행되지 않게 하고, 진행 중인 구매와 같은 주문을 동시에 처리하지 마세요.
전체 흐름
| 순서 | 구분 | 하는 일 |
|---|---|---|
| 1 | 레시피 코드 | 미지급 구매 조회 |
| 2 | 레시피 코드 | 구매 정보 준비 |
| 3 | 앱 코드, 앱 서버, Hive Axyl 서버 API | 영수증 검증과 상품 지급 |
| 4 | 레시피 코드 | 거래 종료 |
| 5 | Hive Axyl SDK | 지급 결과 기록 |
1. 미지급 구매 조회
- 레시피 코드 레시피 코드를 앱에서 호출합니다.
아직 종료되지 않은 주문 목록을 조회한 뒤, 처리하기 전에 조회한 항목을 모두 저장하세요. 모두 저장해 두면 한 건을 처리하다 실패해도 나머지 항목을 잃지 않습니다.
1.1. 미지급 구매 목록 조회
FindUndeliveredAsync()를 호출해 아직 종료되지 않은 주문 목록을 받으세요. serverId를 지정하면 해당 앱 서버의 주문만 조회하고, 생략하면 모든 주문을 조회합니다.
using Hive.Axyl.Samples.Recipes;
var recipe = new UndeliveredPurchaseRecipe(new SteamPurchaseSource());
var query = new UndeliveredQuery(
country: "KR",
language: "ko",
serverId: "server01",
appVersion: Application.version,
accountUuid: accountUuid);
FindUndeliveredOutcome found = await recipe.FindUndeliveredAsync(query, token);
if (found.Status != FindUndeliveredStatus.Success)
{
Debug.LogError($"{found.FailedStep}: {found.BusinessOutcome} {found.Error?.Message}");
return;
}
레시피가 내부에서 수행하는 작업은 아래와 같습니다.
| 구분 | 호출 | 확인할 곳 |
|---|---|---|
| Hive Axyl SDK | RestorePurchasesAsync()로 미완료 거래 조회 | 미완료 거래 복구 |
1.2. 조회한 항목 저장
조회한 항목은 처리하기 전에 모두 Steam 결제 구현에서 설명한 구매 정보 저장소 pendingStore에 저장하고, 2단계부터 한 건씩 순서대로 처리하세요. 목록이 비어 있으면 마무리할 구매가 없다는 뜻이며 오류가 아닙니다.
돌아온 항목에는 결제 당시의 금액과 통화가 이미 들어 있습니다. Hive Axyl 서버가 주문 정보를 보관하고 있기 때문입니다. 화면에 표시된 현재 가격으로 덮어쓰지 말고 그대로 저장하세요.
2. 구매 정보 준비
- 레시피 코드 레시피 코드를 앱에서 호출합니다.
조회한 항목으로 PreparePurchaseAsync()를 호출해 앱 서버에 보낼 구매 정보를 준비하세요. Steam 구매를 복구할 때 이 단계는 Hive Axyl 서버를 호출하지 않고, 조회한 항목에 영수증이 있는지만 확인합니다.
PreparePurchaseOutcome prepared = await recipe.PreparePurchaseAsync(entry, token);
if (prepared.Pending != null)
{
// 준비 단계가 돌려준 값으로 저장한 구매 정보를 교체합니다.
await pendingStore.SaveAsync(prepared.Pending);
}
if (prepared.Status != PreparePurchaseStatus.Success)
{
// 저장한 구매 정보를 그대로 두고 다음 항목으로 넘어갑니다.
continue;
}
3. 영수증 검증과 상품 지급
-
앱 코드 앱에서 직접 구현합니다.
앱 서버 앱 서버에서 직접 구현합니다.
Hive Axyl 서버 API 앱 서버에서 Hive Axyl 서버 API를 호출합니다.
상세 절차: Hive Axyl Server API로 영수증 검증
복구한 구매도 새 구매와 마찬가지로 앱 서버가 영수증을 검증하고 상품을 지급합니다. 2단계의 prepared.Pending을 앱 서버에 보내 구매 복구로 검증과 지급을 요청하고, 앱 서버가 지급 완료로 응답했을 때만 4단계로 진행하세요.
3.1. 앱 서버에 검증과 지급 요청
예제 코드의 VerifyAndGrantOnceAsync()는 Steam 결제 구현에서 구현한 앱의 메서드입니다. 복구에서는 두 번째 인자 requestType으로 구매 복구를 나타내는 2를 전달하세요. 사용 예제에서는 이 인자로 PurchaseVerificationKind.Recovery를 전달하고, 앱 서버 연동 코드가 2로 바꿉니다.
// 앱 서버에 구매 복구로 영수증 검증과 상품 지급을 요청합니다.
PurchaseDeliveryConfirmation delivery = await VerifyAndGrantOnceAsync(
prepared.Pending,
requestType: 2, // 2: 구매 복구. 사용 예제의 PurchaseVerificationKind.Recovery
token);
if (delivery == null)
{
// 앱 서버가 지급을 확인하지 않았습니다.
// 저장한 구매 정보를 그대로 두고 다음 항목으로 넘어갑니다.
continue;
}
3.2. 앱 서버의 영수증 검증과 상품 지급
앱 서버는 Steam 결제 구현과 같은 방법으로 영수증을 검증하고 상품을 지급하세요. 새 구매와 다른 점은 아래와 같습니다.
- 영수증 검증 요청의
requestType에 구매 복구를 나타내는2를 넣습니다. - 새 구매와 같은 지급 기록에서 이미 지급한 구매인지 확인합니다.
requestType은 중복 지급을 막는 기준이 아닙니다. - 이미 지급한 구매라면 다시 지급하지 않고 지급 완료로 응답합니다. 지급 완료로 응답해야 앱이 4단계에서 거래를 종료합니다.
조회한 항목의 Order.IapPayload에는 구매를 시작할 때 전달한 iapPayload가 들어 있습니다. 검증 요청에 이 값을 넣으면 응답의 hiveAxylPayload로 그대로 돌아오므로, 어느 지급 대상이나 서버에 지급해야 하는지를 이 값으로 판단하세요.
4. 거래 종료
- 레시피 코드 레시피 코드를 앱에서 호출합니다.
앱 서버가 지급 완료로 응답하면 ClosePurchaseAsync()를 호출해 구매를 종료하세요. 종료하지 않으면 다음 복구에서 또 조회됩니다.
레시피가 내부에서 수행하는 작업은 아래와 같습니다.
| 구분 | 호출 | 확인할 곳 |
|---|---|---|
| Hive Axyl SDK | FinalizePurchaseAsync()로 서버에 구매 완료 처리 요청 | 구매 완료 처리 |
5. 지급 결과 기록
-
Hive Axyl SDK Hive Axyl SDK를 앱에서 호출합니다.
상세 절차: 상품 지급 결과 저장
지급 결과를 Hive Axyl 서버에 기록하세요. 새 구매를 처리할 때와 같습니다.
AxylTransactionId에는 3.1의 VerifyAndGrantOnceAsync()가 앱 서버 응답에서 따로 보관한 hiveAxylTransactionId를 넣으세요. 이 값은 PurchaseDeliveryConfirmation에 담기지 않습니다.
실패 처리
복구는 여러 건을 순회하므로 한 건이 실패해도 나머지를 계속 처리하세요. 상황별로 앱이 할 일은 아래와 같습니다.
- 조회 결과가 비어 있음: 마무리할 구매가 없는 정상 상태
- 조회 실패: 빈 목록과 구분해야 하는 상태. 오류를 기록하고 다음 실행 때 다시 조회
- 준비 실패: 저장한 구매 정보를 그대로 두고 다음 항목으로 진행
- 앱 서버의 지급 미확인: 저장한 구매 정보를 그대로 두고 다음 항목으로 진행
- 종료 실패: 검증과 지급은 이미 끝난 상태. 다음 복구에서 다시 조회되므로 그대로 두어도 됨
BusinessOutcome의 값별 대응 방법은 결제 레시피의 거절 사유를 참조하세요.
다음 단계
새 구매를 구현하는 절차는 Steam 결제 구현을 참조하세요.