이번 포스트에서는 제가 실제로 경험한 iOS 인앱결제(IAP)와 Apple Server Notification(ASN) 개발 과정에서의 고민과 해결 방법을 정리해 보려고 합니다. 특히, 실시간 구독 상태를 동기화하기 위해 ASN을 백엔드에 통합하는 과정에 집중했습니다.
왜 Apple Server Notification(ASN)을 도입했을까?
기존에는 앱에서 유저가 접속할 때마다 Apple receipt를 백엔드로 전송해서 유효성을 검증했는데요,
이 방식은 실시간성이 떨어지고, 사용자가 앱을 켜지 않으면 구독 상태가 반영되지 않는 문제가 있었습니다.
이를 해결하고자 애플에서 제공하는 실시간 알림 시스템인 ASN을 도입하게 되었습니다.
인프라 구성: Apple → API Gateway → SQS → Backend
애플은 ASN을 외부 HTTP(S) 엔드포인트로 전송하므로, 이를 안정적으로 처리하기 위해 아래와 같은 구조를 구성했습니다.
Apple ASN → API Gateway (HTTPS endpoint) → AWS SQS → Backend 서버
- API Gateway: Apple에서 직접 호출할 수 있는 HTTPS 엔드포인트 제공
- SQS: Apple의 긴 재시도 정책 대응 (ex: 수시간 간격으로 재시도됨)
- Backend: SQS에서 메시지를 받아 구독 상태 업데이트 처리
이 구조 덕분에 유실 없이 비동기 안정 처리가 가능했습니다.
ASN 서명 검증: SignedDataVerifier
Apple ASN은 JWT 포맷의 서명된 데이터를 전송합니다. 이를 검증하기 위해 SignedDataVerifier를 사용하여 ASN의 유효성을 검증하고, payload를 디코딩했습니다.
주의할 점:
- 로컬 테스트에서는 Apple이 메시지를 직접 전송하지 않기 때문에 테스트가 어렵습니다.
- 실제 환경에서는 Apple에서 직접 HTTPS로 메시지를 보내기 때문에 반드시 정식 도메인/SSL 인증서가 필요합니다.
개발 중 겪었던 주요 고민
1. 테스트 어려움
Apple은 로컬 테스트 환경에서는 ASN을 전송하지 않기 때문에, 초기 테스트에 큰 제약이 있었습니다.
API Gateway + SQS 구조를 미리 만들어두고, Apple 콘솔에 등록해서 테스트해야 했습니다.
2. receipt-data 미포함 이슈
ASN에는 receipt-data가 포함되지 않아, 서버에서 별도로 Apple API를 호출해 구독 상태를 확인해야 합니다.
3. Apple의 재시도 정책 대응
ASN 전송 실패 시 Apple은 몇 시간 단위로 재시도하기 때문에, 안정적인 처리를 위해 SQS와 Dead-Letter Queue(DLQ)도 설정해두었습니다.
구현 포인트 정리
- verifySignedData()로 ASN 서명 검증
- Apple에서 보낸 ASN인지 검증하는 함수 - SQS Lambda consumer에서 메시지 처리
- SQS에 쌓인 메시지를 읽고 백엔드로 전달하는 로직 - 구독 상태(AUTO_RENEW_DISABLED, RENEWAL, CANCEL, EXPIRE 등)에 따라 DB 상태 업데이트
마무리
iOS ASN 개발은 쉽지 않았지만, 앱에서 유저가 앱을 열지 않아도 실시간으로 구독 상태를 반영할 수 있다는 점에서 큰 효과가 있었습니다.
'아키텍처 고민' 카테고리의 다른 글
랜덤 문제 풀이 이거 간단하거 아니었네? (0) | 2025.03.27 |
---|---|
Node.js 버전 차이로 인한 장애 대응기 (0) | 2025.03.17 |
Android In-App Purchase RTDN(Real-time Developer Notifications) 개발기 (0) | 2025.03.14 |