Skip to content

Instantly share code, notes, and snippets.

@thejohnlima
Last active July 11, 2020 19:17
Show Gist options
  • Save thejohnlima/7f4c8808ef27bebb90aac3fd9becba2b to your computer and use it in GitHub Desktop.
Save thejohnlima/7f4c8808ef27bebb90aac3fd9becba2b to your computer and use it in GitHub Desktop.
StoryKitManager is a helper for subscription purchase
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let storeManager = StoreKitManager()
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
storeManager.setup()
return true
}
}
import StoreKit
import SwiftyStoreKit
class StoreKitManager {
// MARK: Properties
var sharedSecret: String {
return ""
}
var appBundleId: String {
return Bundle.main.bundleIdentifier ?? ""
}
// MARK: Enums
enum RegisteredPurchase: String {
case weeklysubscription
case yearlysubscription
}
// MARK: Public Methods
func setup() {
SwiftyStoreKit.completeTransactions { purchases in
for purchase in purchases {
switch purchase.transaction.transactionState {
case .purchased, .restored:
let downloads = purchase.transaction.downloads
if !downloads.isEmpty {
SwiftyStoreKit.start(downloads)
} else if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
print("💵 Transaction State ➭ \(purchase.transaction.transactionState.debugDescription): \(purchase.productId)")
default:
break
}
}
}
SwiftyStoreKit.updatedDownloadsHandler = { downloads in
let contentURLs = downloads.compactMap { $0.contentURL }
if contentURLs.count == downloads.count {
print("💵 Content URLs ➭ \(contentURLs)")
SwiftyStoreKit.finishTransaction(downloads[0].transaction)
}
}
}
func getInfo(_ purchase: RegisteredPurchase, completion: @escaping (RetrieveResults?) -> Void) {
SwiftyStoreKit.retrieveProductsInfo([appBundleId + "." + purchase.rawValue]) { result in
completion(result)
}
}
func purchase(_ purchase: RegisteredPurchase,
atomically: Bool = true,
completion: @escaping (PurchaseDetails?, SKError?) -> Void) {
SwiftyStoreKit.purchaseProduct(appBundleId + "." + purchase.rawValue, atomically: atomically) { result in
switch result {
case .success(let purchase):
let downloads = purchase.transaction.downloads
if !downloads.isEmpty {
SwiftyStoreKit.start(downloads)
}
if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
completion(purchase, nil)
case .error(let error):
completion(nil, error)
}
}
}
func verifyPurchase(_ purchase: RegisteredPurchase,
completion: @escaping (VerifySubscriptionResult?, ReceiptError?) -> Void) {
verifyReceipt { result in
switch result {
case .success(let receipt):
let productId = self.appBundleId + "." + purchase.rawValue
switch purchase {
case .weeklysubscription, .yearlysubscription:
let purchaseResult = SwiftyStoreKit.verifySubscription(
ofType: .autoRenewable,
productId: productId,
inReceipt: receipt
)
completion(purchaseResult, nil)
}
case .error(let error):
completion(nil, error)
}
}
}
func restorePurchases(completion: @escaping (RestoreResults) -> Void) {
SwiftyStoreKit.restorePurchases(atomically: true) { results in
for purchase in results.restoredPurchases {
let downloads = purchase.transaction.downloads
if !downloads.isEmpty {
SwiftyStoreKit.start(downloads)
} else if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
}
completion(results)
}
}
private func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: sharedSecret)
SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: completion)
}
}
import UIKit
class ViewController: UIViewController {
private let storeManager = StoreKitManager()
override func viewDidLoad() {
super.viewDidLoad()
validate()
}
@IBAction private func yearlySubscibe() {
storeManager.purchase(.yearlysubscription) { details, error in
print("💵 Purchase Success ➭ \(String(describing: details))")
}
}
@IBAction private func weeklySubscibe() {
storeManager.purchase(.weeklysubscription) { details, error in
print("💵 Purchase Success ➭ \(String(describing: details))")
}
}
@IBAction private func restore() {
storeManager.restorePurchases { results in
print("💵 Restore Purchases ➭ \(results)")
}
}
private func validate() {
storeManager.getInfo(.weeklysubscription) { result in
print("💵 Retrieve Results Weekly ➭ \(String(describing: result?.retrievedProducts.first?.localizedTitle))")
}
storeManager.getInfo(.yearlysubscription) { result in
print("💵 Retrieve Results yearly ➭ \(String(describing: result?.retrievedProducts.first?.localizedTitle))")
}
storeManager.verifyPurchase(.weeklysubscription) { result, error in
guard let error = error else { return }
print("❌ Weekly Error: \(error.localizedDescription)")
self.storeManager.verifyPurchase(.yearlysubscription) { result, error in
guard let error = error else { return }
print("❌ Yearly Error: \(error.localizedDescription)")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment