티스토리 뷰
안녕하세요, 은조공주🥰입니다.
4편으로, 구입을 시작하는 내용을 설명하겠습니다.
( 2021-03-16 기준 Apple document 업데이트 내용 반영되었습니다.)
[ 1.Requesting a Payment from the App Store ]
유저가 구입할 상품을 선택했을 때, 앱스토어로 결제 요청을 제출하기
앱의 스토어 UI 를 노출하면, 유저는 앱 내에서 구입을 할 수가 있습니다. 유저가 상품을 선택했을 때, 앱에서는 결제 요청을 생성해 이를 앱스토어로 제출합니다.
IAP 의 구매 플로우 구현은 3단계로 나뉠 수 있습니다.
먼저 첫번째 단계에서, 앱은 앱스토어로부터 상품 정보를 가져와서, 이를 스토어UI로 유저에게 보여주고, 유저가 상품을 고를 수 있게 합니다. 두번째로, 유저가 앱의 스토어에서 상품을 골랐을 때, 결제를 요청합니다. 그리고 마지막으로 앱이 상품을 제공해줍니다.
Create a Payment Request
유저가 구입할 상품을 선택할 때, 해당 SKProduct 객체를 이용해서 결제요청 (payment request) 을 생성하고, 구입할 수량을 설정합니다.
상품 객체는 앱의 product request 로부터 반환받은 응답 배열에서 사용해야 합니다.
// Use the corresponding SKProduct object returned in the array from SKProductsRequest.
let payment = SKMutablePayment(product: product)
payment.quantity = 2
Submit a Payment Request
Payment request 를 payment queue 에 추가함으로써, 앱스토어에 결제 요청을 제출(?)할 수 있습니다. Queue 에 payment 객체를 두 번 이상 추가하면, 앱스토어에 여러번 제출되고, 유저에게 비용도 그만큼 지불되게 할 것이며 앱에서도 그만큼 상품을 제공해야 합니다.
SKPaymentQueue.default().add(payment)
앱이 제출하는 모든 payment request 에 대해서, 그에 상응하는, 처리해야할 트랜잭션을 받습니다. (receive..)
ARS 상품의 경우, 유저가 할인 제안 등을 받을 수 있는지 판단 후에 그에 대한 내용과 함께 payment request 를 생성해 제출할 수 있습니다. (Implementing Promotional Offers in Your App 참고)
[ 2.Processing a Transaction ]
앱스토어에서 트랜잭션 업데이트를 가져오고, 이를 핸들링하기 위해 transaction queue observer를 등록
앱스토어는 결제 요청을 처리한 이후에, transaction observer 를 호출합니다. 그런 다음 앱은 이후 실행을 위해 구매에 대한 정보를 기록하고, 구입한 컨텐츠를 다운로드하고, 트랜잭션에 대해 완료 처리를 해줍니다.
Monitor Transactions in the Queue
Transaction Queue 는 앱이 StoreKit 을 통해 앱스토어와 통신할 수 있도록 하는 데에 아주 중요한 역할을 합니다. 앱스토어가 무언가 수행해주어야 할 작업을 이 queue 에 추가합니다 ( - 예를 들어 처리되어야 할 payment request ). Payment request 성공 등으로 transaction 의 상태가 바뀌면, StoreKit 은 앱의 transaction queue observer 를 호출합니다. 이를 위해 이 observer 도 지정해주어야 합니다. (어떤 클래스가 이 역할을 수행할지..) 엄청 작고 간단한 앱에서라면, app delegate 에서 StoreKit 과 관련한 모든 로직 ( - transaction queue observing 포함 ) 을 수행할 수 있는데요. 하지만 대부분의 앱에서는 이 observer 로직, 그리고 앱의 다른 스토어 로직들을 처리하는 별도의 클래스를 구현하는 게 좋습니다. 이 Observer 는 SKPaymentTransactionObserver 를 구현해야 합니다.
Observer 를 구현하면, 앱이 활성 트랜잭션의 상태를 지속적으로 폴링할 필요가 없습니다. 결제 요청에 transaction queue 를 사용하여 애플에서 호스팅하는 컨텐츠들을 다운로드하거나, 구독이 갱신되었는지 확인합니다.
다음 예시처럼, 앱 런치 직후에 transaction queue observer 를 추가해야 합니다. (Setting Up the Transaction Observer for the Payment Queue. 참고)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
/* ... */
SKPaymentQueue.default().add(observer)
return true
}
Observer 는, 결제 대기열에 트랜잭션이 추가되었을 때 뿐만 아니라 언제든지 트랜잭션을 처리할 수 있어야 합니다. 예를 들어서, 만약 유저가 앱에서 상품을 구매한 직후에 터널로 들어간다면, 네트워크 유실때문에 구매한 컨텐츠를 전달해주지 못할 수도 있습니다. 그러면 다음 앱 실행때 (Launch), StoreKit 은 앱의 결제 대기열 옵저버를 다시 호출할 것이고 이 때 앱에서 트랜잭션을 다시 핸들링하고 구매한 컨텐츠를 전달해 주어야 합니다. 비슷하게.. 만약 트랜잭션을 완료 상태로 처리하지 않는다면 이 트랜잭션이 완료 처리 될 때까지 앱을 실행할 때마다 옵저버가 호출되겠죠..
앱의 queue observer 에 paymentQueue(_:updatedTransactions:) 요 메소드를 구현해 주어야 합니다. StoreKit 은 트랜잭션의 상태가 바뀔 때마다 (결제 요청이 처리되었다던가?) 해당 메소드를 호출합니다. 다음 표는 Transaction state 에 따라 앱이 해야할 일을 나열합니다.
Status | Action to take in your app |
SKPaymentTransactionState.purchasing | "진행 중" 상태를 나타내도록 UI 를 업데이트하고, 다시 호출되기를 기다립니다. |
SKPaymentTransactionState.deferred | "지연됨" 상태를 나타내도록 UI 를 업데이트하고, 다시 호출되기를 기다립니다. |
SKPaymentTransactionState.failed | error 프로퍼티를 사용하여 유저에게 메세지를 노출합니다. (에러값 목록은 SKErrorDomain 참고) |
SKPaymentTransactionState.purchased | 기능 잠금을 해제하거나, 컨텐츠를 전달하여 구매한 기능을 제공해 줍니다. |
SKPaymentTransactionState.restored | 이전에 구매한 기능을 복원해줍니다. |
대기열의 트랜잭션들은 순서에 상관 없이 상태가 변경될 수 있습니다. 앱은 언제 어떤 트랜잭션이든 작업할 준비가 되어 있어야 합니다. 다음 예시와 같이 트랜잭션 상태에 따라 할 일을 구현해줍니다.
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
// Call the appropriate custom method for the transaction state.
case .purchasing: showTransactionAsInProgress(transaction, deferred: false)
case .deferred: showTransactionAsInProgress(transaction, deferred: true)
case .failed: failedTransaction(transaction)
case .purchased: completeTransaction(transaction)
case .restored: restoreTransaction(transaction)
// For debugging purposes.
@unknown default: print("Unexpected transaction state \(transaction.transactionState)")
}
}
}
Update the App's UI to Reflect Transaction Changes
기다리는 동안 UI 를 최신 상태로 유지하기 위해서, transaction queue observer 는 SKPaymentTransactionObserver 요 프로토콜의 메소드들을 구현할 수 있습니다. (Optional)
- StoreKit 은 큐에서 트랜잭션을 제거할 때 paymentQueue(_:removedTransactions:) 메소드를 호출합니다. 이 메소드 구현부에서, UI 에서 해당 상품을 제거할 수 있도록 하면 됩니다.
- StoreKit 은 트랜잭션 복원을 할 때, 오류가 있었는지 없었는지 에 따라 paymentQueueRestoreCompletedTransactionsFinished(_:) 혹은 paymentQueue(_:restoreCompletedTransactionsFailedWithError:) 를 호출합니다. 이 메소드 구현부에서, 성공 혹은 실패를 반영하도록 UI 를 업데이트 하세요.
성공적으로 처리된 트랜잭션에 대해, 앱은 유저가 구입한 상품을 검증하고 컨텐츠를 언락해주기 위해서 트랜잭션 & 영수증을 검증해야 합니다. ( Validating Receipts with the App Store / 포스팅 5편 참고 )
[ 3.SKPayment ]
앱에서 제공하는 부가 기능에 대한 결제를 처리해달라고 App Store 에 보내는 요청
class SKPayment : NSObject
Payment 객체는 유저가 구입하려는 상품 / 수량을 식별합니다.
Creating Payments
init(product: SKProduct) // 특정 상품에 대한 새로운 결제를 리턴
Getting Payment Details
var productIdentifier: String // 구입하려는 상품의 식별자
var quantity: Int // 유저가 구입하려는 수량
var requestData: Data? // Reserved for future use. (nil 로 보내지 않으면, payment request 가 앱스토어에 의해 리젝된다고 합니다.)
var applicationUsername: String? // 유저 계정에 관련된 identifier
Simulating Buys for Testing
var simulatesAskToBuyInSandbox: Bool // “Ask to Buy” 플로우를 샌드박스에서 태울 것인지 말건지
Getting Discount Details
var paymentDiscount: SKPaymentDiscount?
[ 4.SKMutablePayment ]
앱에서 제공하는 부가 기능에 대한 결제를 처리해달라고 App Store 에 보내는, 가변(Mutable) 요청
class SKMutablePayment : SKPayment
Mutable payment 객체는 유저가 구입하려는 상품 / 수량을 식별합니다.
Payment queue 에 mutable payment 객체가 추가되면, payment queue 는 이 리퀘스트들 queue에 추가하기 전에, immutable request 로 내용을 복사합니다. 앱은 mutable payment 객체의 내용을 안전하게 변경할 수 있습니다.
Getting and Setting Attributes
var productIdentifier: String // 구입하려는 상품의 식별자
var quantity: Int // 유저가 구입하려는 수량
var requestData: Data? // Reserved for future use. (nil 로 보내지 않으면, payment request 가 앱스토어에 의해 리젝된다고 합니다.)
var applicationUsername: String? // 유저 계정에 관련된 identifier
Simulating Buys for Testing
var simulatesAskToBuyInSandbox: Bool // “Ask to Buy” 플로우를 샌드박스에서 태울 것인지 말건지
Getting Discount Details
var paymentDiscount: SKPaymentDiscount? // Payment 에 적용된 할인 정보
[ 5.SKPaymentDiscount ]
Payment 에 적용된 할인 (signed discount)
class SKPaymentDiscount : NSObject
SKPaymentDiscount 에는, SKMutablePayment 에 적용하려고 하는 구독 오퍼 할인 정보가 들어있습니다.
이 객체에, generate된 시그니처를 포함해야 합니다. (Generating a Signature for Subscription Offers 참고)
앱스토어는 이 시그니처 및 매개변수를 사용하여 구독 오퍼를 확인합니다. 트랜잭션이 성공하려면 시그니처가 payment 의 매개변수와 일치해야 합니다.
Initializing a Payment Discount
init(identifier: String, keyIdentifier: String, nonce: UUID, signature: String, timestamp: NSNumber) // 시그니처와, 시그니처에 의해 사용되는 파라미터로 payment discount 객체를 초기화
Identifying the Discount
var identifier: String // 상품의 할인 정보를 식별하기 위한 고유한 string
var keyIdentifier: String // 시그니처를 generate하기 위한 key의 식별자
Validating the Discount
var nonce: UUID // 개발자가 정의하는 UUID (Universally Unique ID)
var signature: String // 암호로 서명된, 특정 할인 혜택의 속성을 나타내는 utf-8 string
var timestamp: NSNumber // 시그니처의 생성 시간을 날짜 및 시간(밀리초), Unix epoch time 으로 포맷팅
[ 6.SKPaymentTransaction ]
Payment queue 내의 transaction 객체
class SKPaymentTransaction : NSObject
이 Payment transaction 객체는 결제(payment)가 결제 대기열 - payment queue에 추가될 때 생성됩니다. 그리고 앱스토어가 결제 처리를 완료했을 때 이 transaction이 앱으로 전송됩니다. 완료된 트랜잭션은 영수증, 트랜잭션id를 제공합니다. (이를 통해 앱에서 처리된 결제에 대한 영구적인 기록을 가지고 있을 수 있습니다.)
Getting Transaction Information
var payment: SKPayment // 트랜잭션에 대한 결제
var transactionIdentifier: String? // 성공적인 결제 트랜잭션을 고유하게 식별하는 string
var transactionDate: Date? // 트랜잭션이 앱스토어의 결제대기열에 추가된 일자
var original: SKPaymentTransaction? // 앱스토어에 의해 복원된 트랜잭션
var error: Error? // 트랜잭션 처리 중 발생한 에러 객체
Getting Downloads
var downloads: [SKDownload] // 트랜잭션에 엮인 downloadable content - download 객체들의 배열
Getting Transaction State
var transactionState: SKPaymentTransactionState // 트랜잭션의 현재 상태
enum SKPaymentTransactionState // 트랜잭션의 상태값을 표현하는 enum 객체
[ 참조 문서 ]
https://developer.apple.com/documentation/storekit/skpayment
https://developer.apple.com/documentation/storekit/skmutablepayment
https://developer.apple.com/documentation/storekit/skpaymentdiscount
https://developer.apple.com/documentation/storekit/skpaymenttransaction
https://developer.apple.com/documentation/storekit/in-app_purchase/processing_a_transaction
'iOS > IAP' 카테고리의 다른 글
[ IAP ] 5. Purchase Validation (7) | 2019.12.16 |
---|---|
[ IAP ] 3. Storefronts (0) | 2019.12.12 |
[ IAP ] 2. Product Information (1) | 2019.12.12 |
[ IAP ] 1. Essentials (2) | 2019.12.11 |
[ IAP ] Overview (0) | 2019.11.12 |
- Total
- Today
- Yesterday
- FinderSync
- Concurrency
- MacOS
- 일상
- IAP
- 인앱결제
- I'm_in_Bamberg
- async/await
- ios iap
- ios 인앱결제
- storekit
- ios
- InAppPurchase
- Apple
- Swift
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |