시작하기
Breeze IAP 설치 및 기본 설정 가이드
시작하기
요구사항
| 항목 | 버전 |
|---|---|
| Unity | 2022.3 이상 |
| Unity In-App Purchasing | 5.3.0 이상 |
설치
Unity Package Manager (Git URL)
- Window → Package Manager 열기
- 좌측 상단 + 버튼 → Add package from git URL… 클릭
- 아래 URL 입력 후 Add
https://github.com/achieveonepark/breeze-iap.gitcom.unity.purchasing 5.3.0 의존성은 Unity Package Manager가 자동으로 설치합니다.
기본 설정
1. 상품 목록 정의
App Store Connect / Google Play Console에 등록한 상품 ID와 타입을 InitializeDto 배열로 작성합니다.
var products = new[]
{
new InitializeDto { ProductId = "gold_100", ProductType = ProductType.Consumable },
new InitializeDto { ProductId = "gold_500", ProductType = ProductType.Consumable },
new InitializeDto { ProductId = "no_ads", ProductType = ProductType.NonConsumable },
new InitializeDto { ProductId = "vip_month", ProductType = ProductType.Subscription },
};ProductType은 UnityEngine.Purchasing 네임스페이스에 있습니다.
2. 초기화
앱 실행 초기에 한 번 InitializeAsync를 호출합니다. 일반적으로 씬 진입 시 가장 먼저 실행되는 MonoBehaviour.Start에서 호출합니다.
private async void Start()
{
await BreezeIAP.InitializeAsync(products, isDebug: true);
}isDebug: true를 전달하면 Unity 콘솔에 상세 로그가 출력됩니다. 출시 빌드에서는 생략하거나 false로 설정하세요.
초기화는 한 번만 — 이미 초기화된 상태에서
InitializeAsync를 다시 호출하면 조용히 무시됩니다.
3. 미확정 구매 처리
초기화 직후 반드시 GetPendingList()를 호출합니다. 이전 세션에서 구매는 완료됐지만 Confirm이 호출되기 전에 앱이 종료된 경우, 해당 구매가 여기에 담겨 있습니다.
var pending = BreezeIAP.GetPendingList();
if (pending != null)
{
foreach (var item in pending)
{
GrantItem(item.Product.definition.id); // 아이템 지급
BreezeIAP.Confirm(item); // 구매 확정
}
}GetPendingList()는 초기화 전에 호출하면 null을 반환합니다.
4. 구매
var result = await BreezeIAP.PurchaseAsync("gold_100");
if (result.IsSuccess)
{
GrantItem(result.Product.definition.id);
BreezeIAP.Confirm(result);
}
else
{
Debug.LogWarning($"구매 실패: {result.ErrorMessage}");
}반드시 Confirm 호출 — 아이템 지급 후
Confirm을 호출하지 않으면 해당 구매가 다음 실행 시GetPendingList()에 다시 나타납니다.
전체 예시
using UnityEngine;
using UnityEngine.Purchasing;
using Achieve.BreezeIAP;
public class ShopManager : MonoBehaviour
{
private async void Start()
{
var products = new[]
{
new InitializeDto { ProductId = "gold_100", ProductType = ProductType.Consumable },
new InitializeDto { ProductId = "no_ads", ProductType = ProductType.NonConsumable },
};
await BreezeIAP.InitializeAsync(products);
// 이전 세션의 미확정 구매 복구
var pending = BreezeIAP.GetPendingList();
if (pending != null)
{
foreach (var item in pending)
{
Grant(item.Product.definition.id);
BreezeIAP.Confirm(item);
}
}
}
public async void OnBuyGoldClicked()
{
var result = await BreezeIAP.PurchaseAsync("gold_100");
if (result.IsSuccess)
{
Grant(result.Product.definition.id);
BreezeIAP.Confirm(result);
}
else
{
ShowErrorPopup(result.ErrorMessage);
}
}
// iOS 복원 버튼 (App Store 정책상 비소모성 상품이 있으면 필수)
public void OnRestoreClicked()
{
BreezeIAP.Restore();
}
private void Grant(string productId)
{
// 상품 ID에 따라 아이템 지급
}
private void ShowErrorPopup(string message)
{
// 오류 안내 UI 표시
}
}에러 처리
PurchaseAsync는 실패해도 예외를 던지지 않고 항상 PurchaseResult를 반환합니다. IsSuccess가 false인 경우 ErrorMessage에 실패 이유가 담겨 있습니다.
| 상황 | IsSuccess | ErrorMessage |
|---|---|---|
| 정상 구매 완료 | true | "" |
| 초기화 전 호출 | false | "초기화 실패" |
| 60초 타임아웃 | false | "결제 시간 초과" |
| 스토어 구매 실패 | false | 스토어 오류 메시지 |
초기화 단계에서 타임아웃이 발생하면 InitializeAsync는 반환되지만 내부 상태가 초기화되지 않은 채로 남습니다. 이후 PurchaseAsync 호출 시 즉시 오류 결과가 반환됩니다.