결제 기능 자체를 처음부터 구현한 건 아니지만, 결제 이후의 프로세스를 개선하는 작업을 진행하게 됐다.
(결제 완료 후에 서버 통신으로 DB 정보를 갱신해준다든가 등등)
보다보니 상품 구매 프로세스 기획 자체에 오류가 있어 테스트를 점점 딥하게 파고들었고,
다음에 인앱 결제 관련 작업을 또 하게 될 경우 참고하고자 포스팅으로 정리해보려 한다.
1. 용어 및 프로세스 훑어보기
- productIdentifier: 앱스토어 커넥트에 등록하는 인앱 혹은 구독 상품의 고유 아이디
- trasactionIdentifier: 결제(거래) 아이디. 각 결제 건을 구분하는 고유 아이디 값이다. 구독 상품이 갱신된 결제 건의 경우에도 새롭게 생성된다.
- originalTransactionIdentifier: 구독 결제의 경우 존재하는, 최초 구독 건의 결제 아이디. 따라서 구독 아이디라고 봐도 좋을 것 같다. 구독 취소 및 기간 만료 후에도 재구독을 하게 될 경우 동일하게 유지된다.
1-a. 간략한 인앱 결제 프로세스
1. 구매할 수 있는 상품 리스트 조회
let request = SKProductsRequest(productIdentifiers: allTicketIdentifiersMob)
request.delegate = self
request.start()
→ 아래 Delegate 호출됨
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse)
response.products: SKProduct 배열
or
func productsRequest(_ request: SKProductsRequest, didFailWithError error: Error)
2. 상품 구매 요청
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
→ 일반적으로 AppDelegate에서 ```SKPaymentQueue.default().add([옵저버 객체])``` 형태로 옵저버 등록함.
옵저버는 ```SKPaymentTransactionObserver``` 프로토콜 채택, 사용자 인앱 결제 이후 아래 함수 호출됨
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])
3. transaction 상태에 따라 이후 처리 진행
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
completeTransaction(transaction)
case .restored:
restoreTransaction(transaction)
case .failed:
failedTransaction(transaction)
default:
break
}
}
}
(위 코드는 예시)
처리 이후에 반드시 ```SKPaymentQueue.default().finishTransaction(transaction)```를 호출하여 완료된 트랜젝션을 제거해줘야 한다.
안 그러면 앱 실행 시마다 paymentQueue가 해당 트랜젝션을 다시 호출할 수 있다고 함.
2. 내가 진행한 테스트 환경 (TestFlight 앱에서 Sandbox 계정 사용)
인앱 결제 테스트 환경에 대한 애플 공식 문서를 보고 싶다면 → 여기🍎
2-a. 이 환경으로 테스트하게 된 이유
소비성 상품도 있기는 했지만, 내가 주로 테스트 해야하는 쪽은 구독 결제 쪽이었다.
백엔드에서 Apple Server API를 통해 구독 상태를 추적하는 과정도 맞물려 있었는데, 이를 위해서는 transacionID와 originalTransactionID 값도 넘겨줘야 하는 상황.
그런데.. 기존에 구현되어 있던 StoreKit 환경에서는 transactionID가 자꾸 1…2…, originalTransactionID 값은 0….
서버에서 추적이 가능할리가 없 ❌
더하여 서버가 구독 상태를 잘 추적하고 있는지를 확인하기 위해서는 도중에 구독 자동 갱신을 취소하는 과정도 확인해봐야 하는데,
왜 다들 자동 갱신 취소는 불가능하다고 하는 거야..
왜 다들 만료될 때까지 기다리라는 거야..
앱스토어 결제 내역에 안 뜨는 건 당연하고, 샌드박스 계정 설정 쪽에 관리 옵션이 있긴 한데 내역을 불러오지도 못하고..
하여간 여러가지 뒤져보고 직접 해보고 하다가 TestFlight+Sandbox 조합의 순간 구독 관리 창도 접근 가능한 걸 확인!
자동 갱신 취소까지는 불확실하지만, 우선 transacionID의 경우는 Sandbox 사용만으로도 Apple Server API를 통해 확인해볼 수 있는 값을 얻을 수 있긴 하다.
(+ 24.12.10)
굳이 테플에 올리지 않아도 Sandbox를 사용하면 Apple Server API를 통해 확인해볼 수 있는 유효한 transacionID를 얻을 수 있고, 자동 갱신 취소도 가능하다!
2-b. 이 환경을 만들기 전 준비해야 할 사항
- 실제 디바이스 (TestFlight로 앱 다운로드도 받아야 하고, AppStore 설정에서 샌드 박스 계정에 대한 구매 관리 화면도 볼 수 있다)
- Apple 계정으로 활성화 되지는 않았으나, 실제 이메일은 받아볼 수 있는 계정 (최초 로그인 시 메일 인증이 필요하다)
3. 테스트 환경 만들기
3-a. 샌드박스 아이디 생성
App Store Connect → 사용자 및 액세스
이메일은 위에서 준비해둔 메일을,
암호는 애플의 깐깐한 암호 규정(대소문자숫자특수문자 조합, 연속되는 글자 불가 기타 등등)을 지켜 칸 채우고 생성해준다.
3-b. 기기에 샌드박스 로그인
TestFlight 앱으로 샌드박스 로그인을 테스트 하려면 앱스토어에서는 로그아웃을 해줘야 하는데,
그러면 TestFlight에서 앱을 다운로드 받을 때 로그인을 요구하므로 앱 다운로드는 미리 받아두자.
샌드박스 로그인 한다고 아예 설정 → 계정 → 로그아웃까지 할 필요는 없고,
그냥 앱스토어 상단 버튼 눌러서 로그아웃 해주면 된다.
![]() |
![]() |
그리고 샌드박스 로그인은 설정 → App Store → 하단 스크롤 ```샌드 박스 계정```에서 진행한다.
→ iOS18 이후에서는 위치가 바뀌었다.
설정 → App Store → 최하단 스크롤 ```샌드 박스 APPLE 계정```
(메일 인증 필요! 혹시 다른 기기에서도 같은 계정으로 샌드박스 로그인했다면 그 기기에서 인증번호 확인 필요!)
로그인 후 ```샌드 박스 계정```을 클릭하면 관리 화면으로 들어갈 수 있는데,
3-c. 인앱 결제 테스트 진행
상품 결제를 시도하면 이렇게 결제창이 뜬다.
참고로 이때의 언어는 계정에 설정한 국가의 언어로 나오게 된다.
샌드박스 로그인을 하지 않아도 TestFlight 환경에서는 원래 사용하던 애플 계정으로도 청구 없이 결제를 진행할 수 있기 때문에,
아래에 표시된 계정이 샌드박스 계정이 맞는지도 같이 확인해주자.
Apple 계정에 로그인하라는 팝업이 먼저 떴다면 샌드박스 계정으로 로그인하면 된다.
![]() |
![]() |
위에서 샌드 박스 로그인을 해줬던 설정 → App Store → 샌드 박스 계정을 다시 클릭하면
결제 테스트를 위한 설정을 관리할 수도 있다.
특히 구독 갱신 주기를 아주 짧게 혹은 아주 길게 설정할 수도 있으며, 구독 관리 화면에서 자동 갱신을 취소할 수도 있다. 기간 만료된 구독 상품을 재구독 하는 것까지도 가능하다.
자동 갱신은 일정 횟수에 한해 자동으로 이뤄지는데, 구글링을 해보면 여기저기 말이 다 다르다. 어디는 8번 어디는 6번 등등..
내 체감 상으로는 5분일 때는 5번 갱신 / 15분일 때는 2번 갱신으로 두 경우 다 30분이면 자동 만료 되는 걸로 보긴 했지만 부정확하다.
(구독에 따른 앱 동작을 테스트한 거지, 애플에서 제공하는 결제 기능을 테스트한 게 아니기 때문에..)
4. 번외
4-a. Run으로는 못 살펴보나요?
위에서도 말했듯 구독 관리 화면까지 접근할 수 있는지는 확실하게 확인해보지 않았지만,
샌드박스로 결제를 테스트해보는 건 물론 가능하다.
(+24.12.10) 구독 관리 화면까지 접근 가능하다!
설정이 조금 귀찮을 수는 있지만, 처음부터 샌드박스로 테스트하고 광명찾자
3번까지의 과정을 똑같이 진행하고 테스트 하면 결제창에서 ```TestFlight```라고 뜨던 텍스트가 ```Sandbox```로 바뀔 뿐이다.
4-b. 샌드박스로 테스트 하고 싶은데 StoreKit으로 떠요
Target → Edit Scheme에서 Run의 StoreKit Configuration을 ```None```으로 변경해준다.
App Store Server API 사용을 위해 앱 개발자가 제공해줄것들
ChatGPT를 보면,플레이스토어/앱스토어/웹 어디서 구독해도 어느 플랫폼에서든 이용할 수 있다.서버 단에서 각 스토어의 구매 내역 및 상태를 조회하여 처리하는 작업을 해주고 있기 때문! 업체
jecklight.tistory.com
<도움 받은 링크들>
'개발노트 > iOS' 카테고리의 다른 글
iOS 프로젝트에서 Kakao Login 설정하기 (0) | 2024.11.27 |
---|---|
Swift에서 싱글톤을 쓰지 마세요 (0) | 2024.11.25 |
iOS에서 API Key 파일 분리하기 (0) | 2024.11.18 |
App Store Server API 사용을 위해 앱 개발자가 제공해줄것들 (2) | 2024.11.15 |
Xcode Preview - No Selected Scheme (0) | 2024.11.13 |