[UIKit] BlogClone: RevenueCat Setup

Junyoung Park·2022년 11월 23일
0

UIKit

목록 보기
98/142
post-thumbnail

Building Subscription Blogging App: Part 4 – RevenueCat Set Up (2021, Xcode 12, Swift 5) – iOS

BlogClone: RevenueCat Setup

구현 목표

  • 인앱 결제를 보다 편리하게 하는 라이브러리 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가 인풋으로 받는 버튼 터치 이벤트의 종류를 구독, 어떤 아웃풋을 내놓을지 결정하는 뷰 모델
  • 특정 동작(구독, 복구 등)에서 어떤 행동을 할지 뷰 모델 내부에서 결정하는 MVVM 스타일

구현 화면

profile
JUST DO IT

0개의 댓글