출시 전 IAP 연동 테스트 중, 전형적이지만 매우 헷갈리는 문제를 만났습니다.

  • 사용자가 “구매 계속”을 누름
  • 버튼이 “처리 중”으로 바뀜
  • 몇 초 뒤 다시 “구매 계속”으로 돌아감
  • App Store 구매 확인 팝업이 뜨지 않음

이 글에서는 실제 추적 경로, 핵심 로그, 근본 원인, 그리고 출시 전 바로 적용 가능한 수정 전략을 정리합니다.

1. 문제 증상

구매 페이지의 상품 목록은 정상 로드됐지만, 구매 버튼을 누른 뒤:

  • purchase() 가 호출됨
  • 시스템 팝업이 나타나지 않음
  • UI가 결국 미구매 상태로 복귀함

처음에는 “구매 플로우가 시작조차 안 된 것”처럼 보였지만, 로그는 다른 사실을 보여줬습니다.

2. 1차 점검: 구매 체인이 실제로 동작하는지 확인

구매 플로우의 핵심 지점에 로그를 촘촘히 추가했습니다.

  • 버튼 클릭 파라미터
  • purchaseSelectedProduct() 진입 및 guard 분기
  • product.purchase() 호출 전/후
  • Transaction.updates
  • refreshEntitlements()
  • Transaction.currentEntitlements
  • Transaction.latest(for:)

결과:

  • purchase().success 반환
  • 트랜잭션 검증 성공, transaction.finish() 도 실행됨
  • 하지만 entitledIDs 는 계속 비어 있음

즉, **문제는 “구매가 시작되지 않음”이 아니라 “구매 후 권한이 인식되지 않음”**이었습니다.

3. 심화 분석에서 나온 결정적 사실

로그를 더 보강하자 결정적인 신호가 나왔습니다.

  1. Transaction.currentEntitlements 반복 수가 0
  2. Transaction.latest(for: monthly) 에는 유효 기록이 있으나 이미 만료됨
  3. 더 중요한 점: 구매 전 Transaction.unfinished 에 오래된 트랜잭션이 존재
  4. 이번 purchase() 가 새 인터랙티브 구매가 아니라 오래된 체인의 트랜잭션을 반환

이게 “팝업이 안 뜨는” 이유를 설명합니다.

  • StoreKit이 먼저 처리 가능한 오래된 트랜잭션(unfinished / 과거 체인)을 반환
  • 코드가 이를 finish() 처리
  • 요청은 “성공”처럼 보이지만 사용자가 기대하는 새 구매 확인 경로로는 가지 않음

4. 근본 원인 요약

단일 원인이 아니라 두 요인이 겹친 문제였습니다.

  • unfinished transaction이 구매 플로우를 간섭
  • sandbox 구독 체인이 만료 상태 (latest transaction이 있어도 active entitlement가 아닐 수 있음)

최종적으로는 “팝업 없음 + 성공처럼 보임 + 권한 비어 있음”으로 나타났습니다.

5. 수정 전략 (실무에서 효과 확인)

5.1 구매 전 unfinished 트랜잭션 선제 정리

앱 시작 시점과 구매 버튼 클릭 전 Transaction.unfinished 를 순회하고, verified transaction에 finish() 를 실행해 오래된 트랜잭션이 새 구매 흐름을 가로채지 못하게 합니다.

5.2 진단 로그 유지 및 강화 (출시 전 권장)

출시 전까지 유지할 핵심 로그:

  • unfinished transaction 스냅샷
  • subscription status (state, renewal info)
  • currentEntitlements 반복 개수
  • latest(for:) 의 transaction/expiration 정보

5.3 권한 판정 “이중 경로” 적용 (선택 강화)

일부 환경에서 currentEntitlements 가 잠시 비는 경우, latest(for:) 를 fallback으로 활용할 수 있습니다(단, active 상태 검증은 필수).

6. 출시 전 IAP 체크리스트

  1. 테스트마다 Sandbox 계정의 구독 상태(만료 여부) 확인
  2. 핵심 경로에서 unfinished 개수 로깅
  3. “첫 구매 / 만료 후 재구독 / 복원 구매” 3가지 시나리오 테스트
  4. currentEntitlementslatest 일치 여부 확인
  5. “팝업이 안 뜸” 발생 시, 먼저 오래된 트랜잭션 경로 적중 여부 확인

7. 결론

“구매를 눌렀는데 팝업이 안 뜸”은 UI 문제나 호출 타이밍 문제만은 아닙니다.
StoreKit 2에서는 트랜잭션 상태, unfinished 큐, 구독 라이프사이클이 최종 동작에 직접 영향을 줍니다.

출시 전에 이 로그와 정리 루틴을 갖춰두면, 운영 환경에서 재현 어려운 IAP 이슈를 크게 줄일 수 있습니다.