티스토리 뷰

iOS/IAP

[ IAP ] 4. Purchases

은조공주 2019. 12. 12. 19:45
반응형

안녕하세요, 은조공주🥰입니다.

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 를 호출합니다. 그런 다음 앱은 이후 실행을 위해 구매에 대한 정보를 기록하고, 구입한 컨텐츠를 다운로드하고, 트랜잭션에 대해 완료 처리를 해줍니다.

Transaction queue를 모니터링하여 구매 프로세스를 완료하고, 상품을 제공합니다.

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)

성공적으로 처리된 트랜잭션에 대해, 앱은 유저가 구입한 상품을 검증하고 컨텐츠를 언락해주기 위해서 트랜잭션 & 영수증을 검증해야 합니다. ( 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/in-app_purchase/requesting_a_payment_from_the_app_store 

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
링크
«   2024/05   »
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 29 30 31
글 보관함