In-app purchase
In-App Purchase API를 사용하면 앱 내에서 디지털 콘텐츠와 서비스를 구매할 수 있는 기회를 사용자에게 제공할 수 있습니다. 사용자는 앱 내에서 구매를 진행할 수 있으며, App Store에서 홍보 중인 제품도 찾아볼 수 있습니다.
StoreKit 프레임워크는 앱을 대신하여 App Store에 연결되어 결제를 안전하게 처리합니다. 이후 프레임워크는 앱에 알림을 보내고, 사용자의 모든 기기에서 In-App Purchase 거래를 앱에서 사용할 수 있도록 합니다. 현재 구매를 나타내는 각 거래에 대해, 앱은 구매된 제품을 사용자에게 제공합니다. 구매를 검증하기 위해 서버에서 거래를 확인하거나, StoreKit의 검증 기능을 사용할 수 있습니다.
아래는 거래 과정에서 StoreKit, 앱, App Store, 서버 간의 상호작용을 나타낸 다이어그램입니다.
App Store는 서버와도 통신할 수 있습니다. App Store Server Notifications를 통해 거래 및 자동 갱신 구독 이벤트에 대해 서버에 알림을 보내고, App Store Server API를 통해 동일한 거래 정보와 추가 정보를 제공합니다.
App Store를 위한 앱 개발 워크플로우에서 In-App Purchases를 추가하는 방법에 대해 알아보려면 App Store Pathway를 참조하세요.
In-App Purchases 및 그 기능, 설정, 테스트 기능, 제품 마케팅 등에 대한 개요는 Simple and safe In-App Purchases를 참조하세요. 구독, 구독 그룹 생성, 가족 공유 등에 대한 개요는 Auto-renewable subscriptions를 참조하세요.
Configure In-App Purchases
In-App Purchase API를 사용하려면 먼저 앱에서 판매할 제품을 설정해야 합니다.
개발 초기 단계에서는 Xcode의 StoreKit 구성 파일에서 제품을 설정하고, App Store Connect에 의존하지 않고 코드를 테스트할 수 있습니다. 자세한 내용은 Setting up StoreKit Testing in Xcode를 참조하세요.
샌드박스 테스트 및 프로덕션 준비가 완료되면, App Store Connect에서 제품을 설정하세요. 앱을 개발하면서 제품을 추가하거나 제거하고, 기존 제품을 수정할 수 있습니다. 자세한 내용은 Configure In-App Purchase settings를 참조하세요.
또한 여러 플랫폼에서 실행되는 앱과 In-App Purchases를 단일 구매로 제공할 수 있습니다. 범용 구매에 대한 자세한 내용은 Add platforms를 참조하세요.
Support a store in your app
In-App Purchase API는 Swift의 concurrency와 같은 기능을 활용하여 In-App Purchase 워크플로우를 간소화하고, StoreKit 뷰를 사용해 SwiftUI로 상점을 구축할 수 있도록 도와줍니다. 이 API를 사용하여 콘텐츠 및 구독에 대한 접근을 관리하고, App Store에서 서명된 거래 정보를 수신하며, 모든 In-App Purchase 거래 기록을 얻을 수 있습니다.
앱 내 상점을 지원하려면 다음 기능을 구현해야 합니다:
transaction listener인 updates를 사용하여 거래 상태 변화를 모니터링하고, 앱이 실행 중일 때 최신 서비스와 콘텐츠를 제공하세요.
StoreKit 뷰를 사용해 제품을 판매하거나, products(for:)를 통해 App Store에서 표시할 제품을 요청하고, purchase(options:)로 구매를 활성화하세요.
currentEntitlements 함수를 사용해 고객의 구매 내역을 순회하고, 구매한 콘텐츠와 서비스를 잠금 해제하세요.
옵션으로, API에서 수신한 서명된 거래 및 구독 상태 정보를 검증할 수 있습니다.
Auto-renewable subscriptions
가입을 간편하게 만들어보세요
Storekit 2
클라이언트 코드를 구현하고 인앱 구매를 위한 버서 구축과 고객의 지원과 환불을 처리하는 세 가지 세션 중 첫번째라고 합니다
StoreKit2는 iOS, macOS, tvOS, watchOS 앱 내 구매를 위한 새 Swift API입니다
비동기인 async/await를 지원하고 있습니다
인앱 구매를 더 쉽고 높은 보안을 제공하고 있습니다
구독을 위한 API가 추가되었습니다
StoreKit2는 기존 Sotrekit 프레임워크 내에 존재합니다
StoreKit2API는 제품, 구매, 거래정보, 거래 히스토리, 구독 상태에 대해서 제공하게 됩니다
Storekit 2 - Products and purchases
StoreKit2에는 구독 정보를 이용해서 고객이 구독 제안을 받을 수 있는지 확인할 수 있고 BakingValue라는 래핑을 추가해서 최신 버전의 StoreKit에서도 이전 데이터에 접근할 수 있도록 했습니다
StoreKit2에서는 정적 함수를 호출해서 제품을 요청하게되면 기존 SKProductRequest와 동일하게 App Store에서 제품 메타 데이터를 얻어오게됩니다
비동기 함수로 통해서 제품 요청과 구매가 한 줄의 코드로 작성이 가능하게되고 구매는 제품 객체의 메서드이기 때문에 검색한 제품을 가져와서 구매를 호출할 수 있습니다
구매는 구매 옵션을 통해서 설정이 가능합니다
구매 옵션에는 수량과 할인을 알 수 있고 어떤 사용자 계정이 거래를 시작하고 완료했는지 볼 수 있는 앱 계정 토큰이 추가되었습니다
앱 계정 토큰은 UUID형식이기 때문에 사용자가 쉽게 생성이 가능하고 구매 오션으로 구매 시 앱 계정 토큰을 보내면 이 토큰이 해당 구매에 대한 거래 정보에 포함이 됩니다
앱 계정 토큰은 모든 기기의 거래 정보에 영원히 유지하게 됩니다
Storekit 2 - Signed transaction info
구매가 처리되면 Storekit2 모든 트랜잭션에 대해 개별적으로 서명된 객체를 제공하고 있습니다
웹에서 공통 표준으로 사용되는 JSON 웹 서명을 사용한 JSON형식으로 제공합니다
서명된 객체에 포함된 모든 정보는 기본 StoreAPI를 통해서 사용할 수 있기 때문에 쉽게 데이터를 작업할 수 있습니다
제품을 정의하고 있는 StoreKit 파일을 만들고 각각 제품을 구별하기 위한 식별자가 포함된 plist를 볼 수 있습니다
구매목록을 하나씩 배열로 확장을 할 수 있는걸 볼 수 있습니다
여기서 제품 정보에 포함된 type이 App Sotre 서버에 정의된 tpye에 대한 속성을 제공하기 때문에 쉽게 구매 유형을 분류할 수 있습니다
종류 | consumable | nonConsumable | autoRenewable |
특징 | 일회성 | 영원히 소유 | 정기적 요금 청구 |
구매를 할 때 해당 제품 객체에서 구매를 호출하게 되면 동시성 함수에 의해 PurchaseResult를 반환하게되고
성공했는지 유무를 알 수 있는데 성공 상태인 경우에만 확인 상태를 받을 수 있고 checkVerified함수를 통해서 결과가 확인되지 않으면 오류를 반환합니다
사용자가 컨텐츠를 얻은 후 StoreKit의 트랜잭션을 완료하고 Purchase메서드를 호출할 때 appAccountToken을 옵션으로 전달해서 현재 접속한 사용자에 대한 토큰을 전달할 수 있습니다
고객은 구매가 발생할 때 부모의 승인과 같은 추가적인 처리가 필요할 때 결과는 보류로 이어지게 됩니다
이러한 트랜잭션을 처리하기 위해서는 이후에 StoreKit에서 발생하는 이벤트를 무한 비동기 시퀀스를 지속적으로 확인해야하고
거래의 결과를 반환받고 이전의 처리와 마찬가지로 기존에 구현한 checkVerified를 통해서 결과를 반환받고 검증하고 updatePurchasedIdentifiers를 통해 UI업데이트를 하게됩니다
결제 사이트에서 구매를 하면 권한을 요청하는 팝업이 표시됩니다
테스트를 진행하기 위해서는 하단의 XCode의 버튼을 눌러 StoreKit 테스트의 트랜잭션 관리자를 열 수 있게됩니다
하단 거래를 선택하고 우측 상단의 승인 버튼을 클릭하게되면 이전에 만든 트랜잭션을 처리하는 함수가 수행되고 UI가 업데이트됩니다
Storekit 2 - Transaction history
완료된 트랜잭션을 추적하기 위해서 새로운 API가 추가되었고 단일 호출로 사용자의 과거 트랜잭션을 접근할 수 있습니다
거기서도 최근 거래 정보만 얻을 수 있고 현재 제품에 대한 정보에 대한 거래 정보도 얻을 수 있습니다
CurrentEntitlements 함수를 통해서 사용자의 거래 내역의 모든 비소모품과 현재 활성화된 모든 구독 거래를 얻어올 수 있습니다.
취소된 항목은 포함되지 않으므로 사용자가 현재 구매하여 활성화된 모든 정보를 얻어올 수 있게 됩니다.
소모품은 거래 내역의 영구적인 요소가 아니기 때문에 때문에 포함되지 않습니다.
StoreKit 2를 사용하면 사용자가 새 기기에 앱을 설치할 때 바로 내역을 얻어올 수 있게 됩니다.
고객이 한 기기에서 구매하면 앱이 설치된 다른 모든 기기에서 구매내역을 확인할 수 있습니다.
실제로 다른 기기에서 구매할 때 앱이 실행 중인 경우 실시간으로 새 거래에 대한 알림을 받게 됩니다.
드물게 사용자가 구매를 했다고 생각하지만 표시되지 않는 경우 App Store 동기화 API를 사용하여 모든 StoreKit 2 트랜잭션을 즉시 재동 기화할 수 있습니다.
이는 restoreCompletedTransactions API를 대체하며 사용자가 동기화를 시작할 수 있도록 하는 UI를 앱에서 제공해야 합니다.
사용자가 수동 동기화를 시작해야 하는 경우 계정을 인증해야 하기 때문에, 사용자 입력에 대한 응답으로만 이 API를 사용해야 합니다.
StoreKit 2 API를 사용하여 이루어진 트랜잭션은 원래 StoreKit API에서 사용할 수 있으며 그 반대의 경우도 마찬가지입니다.
앱에 기존 트랜잭션이 있는 경우 즉시 StoreKit 2 API에서 볼 수 있습니다.
통합 영수증 내에서도 StoreKit 2로 구매한 것을 사용할 수 있습니다.
구독상태는 최신 거래이고 마지막 트랜잭션에 쉽게 접근이 가능합니다
그리고 두 번째는 갱신 상태이고 현재 구독 유무인지 만료되었는지 유예 중인지를 알 수 있습니다
구독 상태의 마지막은 갱신 정보이고 사용자에 대한 구독에 대한 모든 세부 정보를 볼 수 있습니다
사용자가 동일한 제품을 여러 구독을 가지고 있을 수 있기에 배열로 반환하고 있습니다
구독 상태 정보는 사용자가 자동 갱신을 켰는지 여부도 가지고 있습니다
구독에 대해서 자동갱신이 설정된 제품 ID 확인도 가능하기 때문에 다운그레이드 한 경우 이 값을 통해 확인할 수 있습니다
구독이 이미 만료된 경우에는 갱신 정보를 사용하여 만료 이유에 대해서 확인할 수 있습니다
전체 정보에는 중요한 데이터가 포함되어 있기 때문에 JWS를 사용해서 서명됩니다
isPurchase메서드를 통해서 가장 최근 거래정보를 받아올 수 있습니다
StoreKit메서드는 트랜잭션이 StoreKit2의 확인 검사를 통과했음을 얻을 수 있는 결과를 반환하고 이전의 checkVerified메서드를 통해서 결과를 반환받도록 하고 revocationData의 nil 여부를 확인하여 환불도니 거래인지를 알 수 있고 기간 중간에 고객이 업그레이드한 구독은 isUpgraded 플래그가 true로 설정되므로 업그레이드된 트랜잭션을 무시해야 합니다
updateSubscriptionStatus메서드를 통해서 StoreKit에서 구독 상태를 가져와 사용자에게 표시할 수 있습니다
여러 구독 정보를 가지고 있기 때문에 구독 정보를 순회하면서 제공할 수 있는 가장 높은 등급의 서비스를 얻어오게되고
구독의 상태가 만료되었거나 취소되었는지를 확인해야 합니다
currentEntitlements를 호출하게되면 유효한 거래를 가져올 수 있습니다
결과 목록에서 확인된 목록을 필터링할 수 있고 이후 갱신 가능하거나 비소모성 제품에 대해서만 필터링해서 표시할 수 있습니다
JSON웹 서명은 세 부분으로 구성되고 첫 번째는 메타데이터를 포함하는 헤더이고
헤더에는 서명에 사용되는 알고리즘과 서명을 확인하는 데 사용되는 인증서의 위치 같은 중요한 정보가 포함됩니다
StoreKit2는 현재 Swift의 CryptoKit에서 기본적으로 지원되는 ECDSA알고리즘을 사용하게됩니다
인증서는 추가적인 인터넷 ㅇ녀결이 필요하지 않도록 전체 인증서 체인이 JWS데이터에 포함되고 있음을 나타내느 x5c헤더를 사용합니다
두 번째 부분은 페이로드, 거래ID, 상품ID, 구매 날짜 등의 정보를 가지고 있습니다
마지막 부분은 서명 정보이고 헤더와 페이로드를 모두 사용하여 생성되고 있습니다
JWS데이터에서 서명의 유효성을 검사한 후에도 서명된 정보 페이로드에 있는 번들ID가 앱 번들 ID와 일치하는지 확인해야하고
보안을 강화하려면 API 호출에 의존하기 보다 앱의 번들 ID를 어딘가에 포함하고 해당 값을 사용하여 페이로드의 번들 ID와 비교하는 것이 좋습니다
그리고 장치 유효성 검사를 수행해야 합니다
첫 번째 값은 AppStore.deviceVerificationID에서 장치 식별자를 가져온 다음 이를 서명된 정보에서의 deviceVerificationNonce와 합하고 이를 SHA384 hash를 수행해서 hashvalue를 구합니다
이를 두 번째 값인 deviceverification과 비교하여 유효성 검사를 완료할 수 있습니다
Apple 플랫폼에서 앱 내 구매와 자동 갱신 구독을 구현하는 과정을 크게 개선한 새로운 Swift 기반 API를 소개합니다. 주요 기능으로는 비동기/대기(async/await)를 활용한 코드 간소화, 자동 거래 검증, 구독 관리 및 제품 관리 기능이 포함됩니다. 세션에서는 이러한 기능을 앱에 통합하는 방법을 코드 예제를 통해 설명하며, 거래 처리와 구독 관리를 효과적으로 다루는 방법에 대해서 알게되었습니다