-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIAPViewModel.swift
210 lines (175 loc) · 8.28 KB
/
IAPViewModel.swift
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//
// IAPViewModel.swift
// Real News
//
// Created by PC on 4/19/17.
// Copyright © 2017 PC. All rights reserved.
//
import Foundation
import UIKit
import SwiftyStoreKit
enum RegisteredPurchase: String {
case autoRenewablePurchase = "s1"
}
enum SharedSecret:String{
case autoRenewablePurchase = "2389de57454c4f55b1dd9405511b040c"
}
func IAPcompleteTransaction(){
SwiftyStoreKit.completeTransactions(atomically: true) { products in
for product in products {
if product.transaction.transactionState == .purchased || product.transaction.transactionState == .restored {
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
}
}
}
}
func getInfo(_ purchase: RegisteredPurchase,self:StoriesViewController) {
SwiftyStoreKit.retrieveProductsInfo([purchase.rawValue]) { result in
showAlert(alertForProductRetrievalInfo(result,self: self),self: self)
}
}
func alertForProductRetrievalInfo(_ result: RetrieveResults,self:StoriesViewController) -> UIAlertController {
if let product = result.retrievedProducts.first {
let priceString = product.localizedPrice!
let alert = UIAlertController(title: product.localizedTitle, message: product.localizedDescription + " "+priceString+" per year", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Purchase", style: .default, handler: { alert in
purchase(.autoRenewablePurchase,self: self)
}))
alert.addAction(UIAlertAction(title: "Restore Purchase", style: .default, handler: { alert in
restorePurchases(self: self)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
return alert
} else if let invalidProductId = result.invalidProductIDs.first {
return alertWithTitle("Could not retrieve product info", message: "Invalid product identifier: \(invalidProductId)")
} else {
let errorString = result.error?.localizedDescription ?? "Unknown error. Please contact support"
return alertWithTitle("Could not retrieve product info", message: errorString)
}
}
func purchase(_ purchase: RegisteredPurchase,self:StoriesViewController) {
SwiftyStoreKit.purchaseProduct(purchase.rawValue, atomically: true) { result in
if case .success(let product) = result {
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
}
if let alert = alertForPurchaseResult(result, self: self) {
showAlert(alert,self: self)
}
}
}
func alertForPurchaseResult(_ result: PurchaseResult,self:StoriesViewController) -> UIAlertController? {
switch result {
case .success( _):
verifyPurchase(.autoRenewablePurchase,self: self)
return nil
case .error(let error):
print("Purchase Failed: \(error)")
switch error.code {
case .unknown: return alertWithTitle("Purchase failed", message: "Unknown error. Please contact support")
case .clientInvalid: // client is not allowed to issue the request, etc.
return alertWithTitle("Purchase failed", message: "Not allowed to make the payment")
case .paymentCancelled: // user cancelled the request, etc.
return nil
case .paymentInvalid: // purchase identifier was invalid, etc.
return alertWithTitle("Purchase failed", message: "The purchase identifier was invalid")
case .paymentNotAllowed: // this device is not allowed to make the payment
return alertWithTitle("Purchase failed", message: "The device is not allowed to make the payment")
case .storeProductNotAvailable: // Product is not available in the current storefront
return alertWithTitle("Purchase failed", message: "The product is not available in the current storefront")
case .cloudServicePermissionDenied: // user has not allowed access to cloud service information
return alertWithTitle("Purchase failed", message: "Access to cloud service information is not allowed")
case .cloudServiceNetworkConnectionFailed: // the device could not connect to the nework
return alertWithTitle("Purchase failed", message: "Could not connect to the network")
case .cloudServiceRevoked: // user has revoked permission to use this cloud service
return alertWithTitle("Purchase failed", message: "Could service was revoked")
}
}
}
func restorePurchases(self:StoriesViewController) {
SwiftyStoreKit.restorePurchases(atomically: true) { results in
for product in results.restoredProducts where product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
guard let alert = alertForRestorePurchases(results,self: self) else{
return
}
showAlert(alert, self: self)
}
}
func alertForRestorePurchases(_ results: RestoreResults,self:StoriesViewController) -> UIAlertController? {
if results.restoreFailedProducts.count > 0 {
print("Restore Failed: \(results.restoreFailedProducts)")
return alertWithTitle("Restore failed", message: "Unknown error. Please contact support")
} else if results.restoredProducts.count > 0 {
verifyPurchase(.autoRenewablePurchase, self:self)
return nil
} else {
print("Nothing to Restore")
return alertWithTitle("Nothing to restore", message: "No previous purchases were found")
}
}
func verifyReceipt() {
let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: SharedSecret.autoRenewablePurchase.rawValue) { result in
switch result {
case .success(_):
StoriesViewController.purchased.value = true
default: return
}
}
}
func verifyPurchase(_ purchase: RegisteredPurchase,self:StoriesViewController?){
let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: SharedSecret.autoRenewablePurchase.rawValue) { result in
switch result {
case .success(let receipt):
let productId = purchase.rawValue
switch purchase {
case .autoRenewablePurchase:
let purchaseResult = SwiftyStoreKit.verifySubscription(
type: .autoRenewable,
productId: productId,
inReceipt: receipt,
validUntil: Date()
)
let alert = alertForVerifySubscription(purchaseResult)
guard let unwrappedself = self else{
return
}
showAlert(alert, self: unwrappedself)
}
case .error(let error):
if case .noReceiptData = error {
SwiftyStoreKit.refreshReceipt { result in
switch result{
case .success(receiptData: _): verifyPurchase(.autoRenewablePurchase, self: self)
default: break
}
}
}
}
}
}
func alertWithTitle(_ title: String, message: String) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
return alert
}
func showAlert(_ alert: UIAlertController,self:StoriesViewController) {
self.present(alert, animated: true, completion: nil)
}
func alertForVerifySubscription(_ result: VerifySubscriptionResult) -> UIAlertController {
switch result {
case .purchased(let expiresDate):
StoriesViewController.purchased.value = true
return alertWithTitle("You are subscribed!", message: "Subscription is valid until \(expiresDate)")
case .expired(let expiresDate):
return alertWithTitle("Product expired", message: "Product is expired since \(expiresDate)")
case .notPurchased:
return alertWithTitle("Not purchased", message: "This product has never been purchased")
}
}