Building Subscription Blogging App: Part 4 – RevenueCat Set Up (2021, Xcode 12, Swift 5) – iOS
RevenueCat
사용RevenueCat
API 등록func getSubscriptionStatus(completion: @escaping(Bool) -> Void) {
Purchases.shared.getCustomerInfo { [weak self] info, error in
guard
let entitlements = info?.entitlements,
let isEntitlementActive = entitlements.all["Premium"]?.isActive,
error == nil else {
completion(false)
return
}
self?.premium.send(isEntitlementActive)
completion(isEntitlementActive)
}
}
func subscribe(package: Package, completion: @escaping(Bool) -> Void) {
if premium.value {
completion(true)
return
}
Purchases.shared.purchase(package: package) { [weak self] _, info, error, userCancelled in
guard
let entitlements = info?.entitlements,
let isEntitlementActive = entitlements.all["Premium"]?.isActive,
error == nil,
!userCancelled else {
completion(false)
return
}
self?.premium.send(isEntitlementActive)
completion(isEntitlementActive)
}
}
func fetchPackages(completion: @escaping(Package?) -> Void) {
Purchases.shared.getOfferings { offerings, error in
guard
let package = offerings?.offering(identifier: "default")?.availablePackages.first,
error == nil else {
completion(nil)
return
}
completion(package)
}
}
RevenueCat
API에서 등록한 패키지를 리턴하는 함수func restorePurchases(completion: @escaping(Bool) -> Void) {
Purchases.shared.restorePurchases { [weak self] info, error in
guard
let entitlements = info?.entitlements,
let isEntitlementActive = entitlements.all["Premium"]?.isActive,
error == nil else {
completion(false)
return
}
self?.premium.send(isEntitlementActive)
completion(isEntitlementActive)
}
}
import Foundation
import Combine
class PayWallViewModel {
enum Input {
case viewDidLoad
case didTapSubscribe
case didTapRestore
}
enum Output {
case isSubscribed(Bool)
case isRestored(Bool)
}
private let output: PassthroughSubject<Output, Never> = .init()
private var cancellables = Set<AnyCancellable>()
private let iapService = IAPService.shared
func transform(input: AnyPublisher<Input, Never>) -> AnyPublisher<Output, Never> {
input
.sink { [weak self] result in
switch result {
case .didTapRestore: self?.handleRestore()
case .didTapSubscribe: self?.handleSubscribe()
case .viewDidLoad: break
}
}
.store(in: &cancellables)
return output.eraseToAnyPublisher()
}
private func handleRestore() {
iapService.restorePurchases { [weak self] isRestored in
self?.output.send(.isRestored(isRestored))
}
}
private func handleSubscribe() {
iapService.fetchPackages { [weak self] package in
guard let package = package else { return }
self?.iapService.subscribe(package: package, completion: { [weak self] isSubscribed in
self?.output.send(.isSubscribed(isSubscribed))
})
}
}
}
PayWallViewController
가 인풋으로 받는 버튼 터치 이벤트의 종류를 구독, 어떤 아웃풋을 내놓을지 결정하는 뷰 모델