From 058325d6d2207ae3bf0268e5f5ac7658f8234da4 Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Thu, 25 Jun 2020 11:52:43 +0200 Subject: [PATCH 1/9] fixed xcode 12 --- SwiftyStoreKit/OS.swift | 18 +++- SwiftyStoreKit/PaymentQueueController.swift | 106 ++++++++++---------- SwiftyStoreKit/SwiftyStoreKit.swift | 7 -- 3 files changed, 65 insertions(+), 66 deletions(-) diff --git a/SwiftyStoreKit/OS.swift b/SwiftyStoreKit/OS.swift index 9ad543e7..69c54ab8 100644 --- a/SwiftyStoreKit/OS.swift +++ b/SwiftyStoreKit/OS.swift @@ -35,14 +35,22 @@ import StoreKit #endif // MARK: - Missing SKError on watchOS -#if os(watchOS) +#if os(watchOS) && swift(<5.3) public struct SKError: Error { - var Code: SKErrorCode = .unknown - var _nsError: NSError? + public typealias Code = SKErrorCode - static var unknown: SKErrorCode = .unknown - static var paymentInvalid: SKErrorCode = .paymentInvalid + let _nsError: NSError + + init(_nsError: NSError) { + self._nsError = _nsError + } + + var code: Code { + return Code(rawValue: _nsError.code) ?? .unknown + } + static var unknown: Code = .unknown + static var paymentInvalid: Code = .paymentInvalid } #endif diff --git a/SwiftyStoreKit/PaymentQueueController.swift b/SwiftyStoreKit/PaymentQueueController.swift index 0fac661c..758dafd2 100644 --- a/SwiftyStoreKit/PaymentQueueController.swift +++ b/SwiftyStoreKit/PaymentQueueController.swift @@ -26,7 +26,7 @@ import Foundation import StoreKit protocol TransactionController { - + /// Process the supplied transactions on a given queue. /// - parameter transactions: transactions to process /// - parameter paymentQueue: payment queue for finishing transactions @@ -41,30 +41,32 @@ public enum TransactionResult { } public protocol PaymentQueue: class { - + func add(_ observer: SKPaymentTransactionObserver) func remove(_ observer: SKPaymentTransactionObserver) - + func add(_ payment: SKPayment) func start(_ downloads: [SKDownload]) func pause(_ downloads: [SKDownload]) - #if os(watchOS) - func resumeDownloads(_ downloads: [SKDownload]) - #else func resume(_ downloads: [SKDownload]) - #endif func cancel(_ downloads: [SKDownload]) func restoreCompletedTransactions(withApplicationUsername username: String?) - + func finishTransaction(_ transaction: SKPaymentTransaction) } -extension SKPaymentQueue: PaymentQueue { } +extension SKPaymentQueue: PaymentQueue { + #if os(watchOS) && swift(<5.3) + public func resume(_ downloads: [SKDownload]) { + resumeDownloads(downloads) + } + #endif +} extension SKPaymentTransaction { - + open override var debugDescription: String { let transactionId = transactionIdentifier ?? "null" return "productId: \(payment.productIdentifier), transactionId: \(transactionId), state: \(transactionState), date: \(String(describing: transactionDate))" @@ -72,9 +74,9 @@ extension SKPaymentTransaction { } extension SKPaymentTransactionState: CustomDebugStringConvertible { - + public var debugDescription: String { - + switch self { case .purchasing: return "purchasing" case .purchased: return "purchased" @@ -87,24 +89,24 @@ extension SKPaymentTransactionState: CustomDebugStringConvertible { } class PaymentQueueController: NSObject, SKPaymentTransactionObserver { - + private let paymentsController: PaymentsController - + private let restorePurchasesController: RestorePurchasesController - + private let completeTransactionsController: CompleteTransactionsController - + unowned let paymentQueue: PaymentQueue - + deinit { paymentQueue.remove(self) } - + init(paymentQueue: PaymentQueue = SKPaymentQueue.default(), paymentsController: PaymentsController = PaymentsController(), restorePurchasesController: RestorePurchasesController = RestorePurchasesController(), completeTransactionsController: CompleteTransactionsController = CompleteTransactionsController()) { - + self.paymentQueue = paymentQueue self.paymentsController = paymentsController self.restorePurchasesController = restorePurchasesController @@ -118,7 +120,7 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver { let message = "SwiftyStoreKit.completeTransactions() must be called when the app launches." assert(completeTransactionsController.completeTransactions != nil, message) } - + func startPayment(_ payment: Payment) { assertCompleteTransactionsWasCalled() @@ -126,45 +128,45 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver { skPayment.applicationUsername = payment.applicationUsername skPayment.quantity = payment.quantity - if #available(iOS 12.2, tvOS 12.2, OSX 10.14.4, *) { + if #available(iOS 12.2, tvOS 12.2, OSX 10.14.4, watchOS 6.2, *) { if let discount = payment.paymentDiscount?.discount as? SKPaymentDiscount { skPayment.paymentDiscount = discount } } -#if os(iOS) || os(tvOS) - if #available(iOS 8.3, *) { + #if os(iOS) || os(tvOS) || os(watchOS) + if #available(iOS 8.3, watchOS 6.2, *) { skPayment.simulatesAskToBuyInSandbox = payment.simulatesAskToBuyInSandbox } -#endif - + #endif + paymentQueue.add(skPayment) - + paymentsController.append(payment) } - + func restorePurchases(_ restorePurchases: RestorePurchases) { assertCompleteTransactionsWasCalled() - + if restorePurchasesController.restorePurchases != nil { return } - + paymentQueue.restoreCompletedTransactions(withApplicationUsername: restorePurchases.applicationUsername) - + restorePurchasesController.restorePurchases = restorePurchases } - + func completeTransactions(_ completeTransactions: CompleteTransactions) { - + guard completeTransactionsController.completeTransactions == nil else { print("SwiftyStoreKit.completeTransactions() should only be called once when the app launches. Ignoring this call") return } - + completeTransactionsController.completeTransactions = completeTransactions } - + func finishTransaction(_ transaction: PaymentTransaction) { guard let skTransaction = transaction as? SKPaymentTransaction else { print("Object is not a SKPaymentTransaction: \(transaction)") @@ -181,22 +183,18 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver { } func resume(_ downloads: [SKDownload]) { - #if os(watchOS) - paymentQueue.resumeDownloads(downloads) - #else paymentQueue.resume(downloads) - #endif } func cancel(_ downloads: [SKDownload]) { paymentQueue.cancel(downloads) } - + var shouldAddStorePaymentHandler: ShouldAddStorePaymentHandler? var updatedDownloadsHandler: UpdatedDownloadsHandler? - + // MARK: SKPaymentTransactionObserver func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { - + /* * Some notes about how requests are processed by SKPaymentQueue: * @@ -221,39 +219,39 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver { var unhandledTransactions = transactions.filter { $0.transactionState != .purchasing } if unhandledTransactions.count > 0 { - + unhandledTransactions = paymentsController.processTransactions(transactions, on: paymentQueue) - + unhandledTransactions = restorePurchasesController.processTransactions(unhandledTransactions, on: paymentQueue) - + unhandledTransactions = completeTransactionsController.processTransactions(unhandledTransactions, on: paymentQueue) - + if unhandledTransactions.count > 0 { let strings = unhandledTransactions.map { $0.debugDescription }.joined(separator: "\n") print("unhandledTransactions:\n\(strings)") } } } - + func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) { - + } - + func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) { - + restorePurchasesController.restoreCompletedTransactionsFailed(withError: error) } - + func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { - + restorePurchasesController.restoreCompletedTransactionsFinished() } - + func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) { - + updatedDownloadsHandler?(downloads) } - + #if os(iOS) && !targetEnvironment(macCatalyst) func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool { diff --git a/SwiftyStoreKit/SwiftyStoreKit.swift b/SwiftyStoreKit/SwiftyStoreKit.swift index 31d716a7..7e51a14e 100644 --- a/SwiftyStoreKit/SwiftyStoreKit.swift +++ b/SwiftyStoreKit/SwiftyStoreKit.swift @@ -118,17 +118,10 @@ public class SwiftyStoreKit { return RestoreResults(restoredPurchases: restoredPurchases, restoreFailedPurchases: restoreFailedPurchases) } - #if os(watchOS) - private func storeInternalError(code: SKErrorCode = SKErrorCode.unknown, description: String = "") -> SKError { - let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ]) - return SKError.init(Code: code, _nsError: error) - } - #else private func storeInternalError(code: SKError.Code = SKError.unknown, description: String = "") -> SKError { let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ]) return SKError(_nsError: error) } - #endif } extension SwiftyStoreKit { From fc5ea145a65a90a0f355594ed98a18ac8e0008bf Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Thu, 25 Jun 2020 13:57:43 +0200 Subject: [PATCH 2/9] fixec package --- Package.swift | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 2cc94edf..90314278 100644 --- a/Package.swift +++ b/Package.swift @@ -3,14 +3,30 @@ import PackageDescription let package = Package( name: "SwiftyStoreKit", - // platforms: [.iOS("8.0"), .macOS("10.10"), tvOS("9.0"), .watchOS("2.0")], + platforms: [ + .iOS(.v8), + .tvOS(.v9), + .watchOS("6.2"), + .macOS(.v10_10) + ], products: [ - .library(name: "SwiftyStoreKit", targets: ["SwiftyStoreKit"]) + // Products define the executables and libraries produced by a package, and make them visible to other packages. + .library( + name: "SwiftyStoreKit", + targets: ["SwiftyStoreKit"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), ], targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "SwiftyStoreKit", - path: "SwiftyStoreKit" - ) + dependencies: []), + .testTarget( + name: "SwiftyStoreKitTests", + dependencies: ["SwiftyStoreKit"]), ] ) From d3194d98cf06a439aba2fe7f9dd146fd8d59e7bd Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Thu, 25 Jun 2020 14:00:21 +0200 Subject: [PATCH 3/9] fix version --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 90314278..67f2f856 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.2 +// swift-tools-version:5.0 import PackageDescription let package = Package( From 88f266f60413a0333e1cba8e6cdc56786866b702 Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Thu, 25 Jun 2020 14:03:08 +0200 Subject: [PATCH 4/9] fix path --- Package.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 67f2f856..58c26dfb 100644 --- a/Package.swift +++ b/Package.swift @@ -24,9 +24,11 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "SwiftyStoreKit", - dependencies: []), + dependencies: [], + path: "SwiftyStoreKit"), .testTarget( name: "SwiftyStoreKitTests", - dependencies: ["SwiftyStoreKit"]), + dependencies: ["SwiftyStoreKit"], + path: "SwiftyStoreKitTests"), ] ) From 0dd27cea1619da09b5908f6b2b26460a8cdb6b15 Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Fri, 26 Jun 2020 17:03:26 +0200 Subject: [PATCH 5/9] fix package --- Package.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 58c26dfb..67f2f856 100644 --- a/Package.swift +++ b/Package.swift @@ -24,11 +24,9 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "SwiftyStoreKit", - dependencies: [], - path: "SwiftyStoreKit"), + dependencies: []), .testTarget( name: "SwiftyStoreKitTests", - dependencies: ["SwiftyStoreKit"], - path: "SwiftyStoreKitTests"), + dependencies: ["SwiftyStoreKit"]), ] ) From 3a52abb35bde9a8733b9d71fbe23e47a8e6b8790 Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Fri, 26 Jun 2020 17:07:37 +0200 Subject: [PATCH 6/9] fix Sources --- Sources/AppleReceiptValidator.swift | Bin 0 -> 976 bytes Sources/CompleteTransactionsController.swift | Bin 0 -> 984 bytes Sources/InAppProductQueryRequest.swift | Bin 0 -> 980 bytes Sources/InAppReceipt.swift | Bin 0 -> 968 bytes Sources/InAppReceiptRefreshRequest.swift | Bin 0 -> 980 bytes Sources/InAppReceiptVerificator.swift | Bin 0 -> 980 bytes Sources/OS.swift | Bin 0 -> 1016 bytes Sources/PaymentQueueController.swift | Bin 0 -> 1036 bytes Sources/PaymentsController.swift | Bin 0 -> 972 bytes Sources/ProductsInfoController.swift | Bin 0 -> 976 bytes Sources/RestorePurchasesController.swift | Bin 0 -> 980 bytes Sources/SKProduct+LocalizedPrice.swift | Bin 0 -> 980 bytes Sources/SKProductDiscount+LocalizedPrice.swift | Bin 0 -> 988 bytes Sources/SwiftyStoreKit+Types.swift | Bin 0 -> 976 bytes Sources/SwiftyStoreKit.swift | Bin 0 -> 1028 bytes 15 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Sources/AppleReceiptValidator.swift create mode 100644 Sources/CompleteTransactionsController.swift create mode 100644 Sources/InAppProductQueryRequest.swift create mode 100644 Sources/InAppReceipt.swift create mode 100644 Sources/InAppReceiptRefreshRequest.swift create mode 100644 Sources/InAppReceiptVerificator.swift create mode 100644 Sources/OS.swift create mode 100644 Sources/PaymentQueueController.swift create mode 100644 Sources/PaymentsController.swift create mode 100644 Sources/ProductsInfoController.swift create mode 100644 Sources/RestorePurchasesController.swift create mode 100644 Sources/SKProduct+LocalizedPrice.swift create mode 100644 Sources/SKProductDiscount+LocalizedPrice.swift create mode 100644 Sources/SwiftyStoreKit+Types.swift create mode 100644 Sources/SwiftyStoreKit.swift diff --git a/Sources/AppleReceiptValidator.swift b/Sources/AppleReceiptValidator.swift new file mode 100644 index 0000000000000000000000000000000000000000..70fdf1f2d7593ee9ea94cb473cf31696d7ae71e3 GIT binary patch literal 976 zcmZ9KJx>&25XWbEF_I8j4kJWK+@Ot#=dJg~YDm20PD3Ilh7~%C%N|_bU^2)_t+1$%t+>j)3(`XdDVw3Y(Lil24OUfXtCurTisCP*WC4BNOGm1yjk<= zVQ+pbXl`7RytC!6gfE>iX!0A0u1VZ(G^*Z$SN8lyxa3y-ii?svEv}|XuDL+OgBsA= z&;oQ`v;un(I)FJpH~@(9^V>Xi?602lZ_SLI$*=!vQnPzv5TD z`>9lFn9n2r#4Y>vFlenAb0u}2c8oQwJD%xa@9OJB?)gnQleWyFWt#cq!)&^k%v#g= z$S}M{uFGE8TYHy{bk_)J2NX$cZ$C91Bgn% zUPhn4olb{)vRr}kpZYfP@GpWVC8>j-3Kzfy;b-6%!izn;1a3&Y&mc18I}Cz%B(8%$ z3Xg(+2q(awg~z~$!UkBEJ|!bTet6KhL!B;Xz?5F-%SOZTZwIvOD%D;R zf*RJLx1cl7N32V*{m=yZeQyCE%CBrw_p!fn!M`~@bS}U4yM^1w^`n2z`{V4Zo(@p^ z5qb*!3jGO9U{=FW>Vf80Z9TC*d^y=2gR5b8q#~J!P7*>{3TkK6|X$(X8S?-<3YY`IXIHLH`QVxf9p^}kJPpx-gNZc9w(=U~gkxZjfJE&~7GnOKRs zQ}oF9ASwY%^ZVOww`ot35h#7JZzB)iBsjy#B={Ng40w)t9{ielp^Kk_UvRuf$A5y~ zp%1*z@g(?=IR*a4oCbel9s-{+>)Evao|(2N;IYG@`}8@q=C{@*CAP@1o=?Uai$|nqhx_ z%k$SqC2w!J%i*>idOp9A=!(RjG_B3eIp3?dYT=8P<8RM9uUk$K-U|2t(Pgf?K*Ylu z(3{W_^qFWKb_6zf{_}6#8#|X@``f|Ie=lyB%)l3JdZ9|Ws zKcUA^!k%;}&%nF0I`j7DAKwn9IEC&=MKTk;iAY%vY8Y4To$J&+dbfykf26;LgQbk%#{gY)DcEF9?^w72yT&8{x%1ehCgGK41{#50ds=wAIdM`BzFjA2u+eEt(*N)mgkQ Hm!$tGDS>SH literal 0 HcmV?d00001 diff --git a/Sources/InAppReceipt.swift b/Sources/InAppReceipt.swift new file mode 100644 index 0000000000000000000000000000000000000000..4fa0ce8cc5a2d3bca5ed1c8c6ae9a34bad1ed942 GIT binary patch literal 968 zcmZ9KKTH#G6vy8|YcL_CEk=xxZ~+HREUo>=VMyR?H5g^##Eqep!yedP(;gut7-eT* zWFcX2aByT`V1UNafx*!@8CM-((S-7S*Z1=ZFL`~R_viQS{ob#OuDeQ*O0n)+1I)V9 z&CyVVf9)5JcYYX6k6KNWeHO0^S=er_1B78TjcC4M*BkAS?^lW|?oG)R+|pXbu6mvM zb+^9SCwXh#S@t$8&#m(piDD9eUNvjAIlE*#HE*oJMMOiKyFtVQ>d=SKY3NJQCDoM@zqQpQF{RW0{sU42|a^`upgd* z_hmNctj|Awy}tujLwBTn8TP+Kq$~$DjEf`wuDMR#qkW4YcP{-kEPUB{Yd=mT61{vL z@!4X@sd{dstj`qGdD_>@SYJyc_W$3#h+$U`FO?{&&4N<^msg* zDm=@Zk22|$`9#gX#b=JIW|?unrK+_Ea`u3?FQXN0H0hVUzJO?bY8UxUjM@6w6x%R7X@yAqFpKM6;{--Tn~ zBjJAVS79C8BYl!!)n7X%+LW3o7%5+3$3)u_*G_}_2$xL`cY6O@%~E0s;X`+_EvG=@a6%iG%H`s#GMp zG4KHxKw@BIVCV-3nHW1VAx5@#VF5w-pK}jRIq7`AdwI_HoW17zn*?dsgV@?&);HrE zoiO>S9(d93+4K2JZr@>_<;57Xu;W|@n1nG5qSa6Z;V=~Y?fQm)MsiiZvE5dkXf(g$ z2b2_#(Px6PWd_3xH_9w9k_#{?q^bD>tW4b-NFzQ^zuN$!XAH?aJsx22Xd znao)}kNBf{!|OzT*s|_b^?7<{wXpJJrcVb8&r`)Gm*q^(&Q|Pfwv@h8$W_t>d#RMZ zVdt09#a#7n#kpR{=bYPm{(U|JJ;LfnEi=DA16yRq{nk6)8t~tpnYHLU#UJ?=L?>Wp z(C5!!FyNjnvrzt9U&S8&N3bPH6TBi^23Lhwz z0)H1yfjOrurY+-6a$GP#|R-&2{wlQ z0Sq8@=-8nHe?Xe4BO_DQv0GUxRYfBGo^wAEIO%+!d;HG#JA2jhHVINL_@OnytjFCP z?a}$^ym5o`(s=TL-LTka+3!LYwwvn!y)c?av{ZBaS}PR#<-&&7C%L>=+%7wnpfkVY z`I`fhw|Cr9uxkgN&u=7}lK88NRjn>KMaQiM%Z~4s++qPm(>1O~%_P^|A>v^T=woOW z`c`xe_Aaysv!2)hi1ITBJbBxHf6IR~KXfC%@vniKx9dkQZ~9Z>tC_x{whldm{)ApY z3479^JOl5}YAo1ae*Aqs#wm11DwKQSn~0Ru>6v{pqI4`^i-V1X)FP;oX{{(M((HJ$>?`-F>g-O1h&&<5{cHZfa)${Xmgx8iw4kpISE(iNslsk-t~1*)7j$ zujqG5YCpZwS1{V3rw<3?&!gGLmt{}NNEVG`G8doAq>Ay3F_Vj5H_|ilY^rp-SeVYF zQ-xcq|83p_eZ%MmJu`nl0Y5H$->fW@)dRR&$1AWKw&l)So55Y)o+irjdd#EVvX_BJ zGh$YzX5c@Hn=n;?*YVwdygZ~OA!RmaiL$ogWQ7}rrMLR@WlGhG{^${?? W7q-}U^xsFC1TRUSS3`vG2+9kK`dv3F7dlx!f9@HEn;zkYVd1wK; zAX=bxLKK9FDg*~hKJ`q;07{`QBrL0BysG-&;x*837~QC4=JS)VapBumWobb@iko%(VyEHQ-n`ul z@AB#}QI6{|k9yl#0sfm2vl2Cf;89$Gs06HmbN>tm1MYz(2IZIiH1P0t!84N7!HdEL za6$Mk_@QuRgqOh^5|0=}Dfw>`;2nwU;1|ME;4i{a@H^pY@V>AC)@7d*SnaRv5j~Nb mDKJujME8iENnHCF*6Uz?FD$X|nBNfTG`K1I&qe6*ec``+XLtty literal 0 HcmV?d00001 diff --git a/Sources/PaymentsController.swift b/Sources/PaymentsController.swift new file mode 100644 index 0000000000000000000000000000000000000000..7764dff238e5740e1f619add418eced9e8153579 GIT binary patch literal 972 zcmZ9K&r2Io5Xay83k8uF#fS(lwU1GDp)A8&Tv?5;?;Eg+?Wr>q4gJ#D3E zTZo>{d)HrD7)p-XwJiB0do9Sqwo)CS9mX((Sgbf+r4dqosjwxxIG2~JJ0+*=H|KYy zx81{ed)Hm}_ibN#^hO~DIsUP*ua4zp+4p3z=y-1`R60!g4k2hr6Z#rD1D$7GgYAU2 zVa9VC0MUNth$asFjc5L=slF%qtv@x~IH-^Oed?R+>zOW5`vv+9dJFvl{SEEJj%Wtj zS+=%dU)@FS)jiQ2DJ3K7O+si(K?CFJeN!FvpnElL5#)Yxe*;TjcZ<$sEEemg^N4>a zth!}iRyNJKygn~3%uTF1nCa{F&_Ou8{F2Wkta#3f$1~BlsYEWCvc@yf2`f1sO(*j2 za@ny|GLfCt^B>U}=mS>QY>DapG1xRQ?zdKUSAdUqCf1_wq(1UAL?>YT(dS>iUZ|5crC@7yO+$46ZWw xfp3^ia5wjfgLQwSD#Rhz^n#I660Qny!g1p!s1JeZ`;$a|Vt)-3FTfV}{|^QWY5xEK literal 0 HcmV?d00001 diff --git a/Sources/ProductsInfoController.swift b/Sources/ProductsInfoController.swift new file mode 100644 index 0000000000000000000000000000000000000000..10366539496e530b84f8660216312ea0e60577d4 GIT binary patch literal 976 zcmZ9KJ#W)s5XaAbK}D*No1zv~m9T&XM2N{-4XQ*!0s;Y2!IX_5O&sbr@q=tv1q4GS z20j1-3sOHo2P7C7O2o*(z=*`chy)7^fC&F{?!hT1o$q%q&-tFSSCm>ONVgFt)&a9V z8|CPj$xrW!AOCncS2*hSs_e5o96=U#lS5QnPM@xoIPmnSv*hOQT)lIy)AtzMBF%l5{stD`_B-C$ zTrM}s=MlfwX!=2{qE+isU7x3IYZdEGXL|E$?op<6`n?Q-@)F<;9TorQAt zj8j<1mh$zBwd(0&AzwYO=ilNp(63nCuw~}==U_|BxL+&qSAhTS%&bM?&{f7MwkdA;C GrTCcEVj?DnrQST0ve<>TPqMp&NHCF` z2R?uYNIZD-;DHZNd-BN98y>yM#RHmH|FfOPEle^yzj=9P=b7CVr8WrCs`-(%!L0kk z933(F=|1(s-uBh(b*EcmpXKckvarKk2N;Dh45Dh_`awSw`K{Wzx+uAds&BU3b~u>d zQvSxcVEqv{S%I7x{SrT7z1CBl4^y`gU;09&Y4t>>Zy8fMjkIZu21tK1n&)kL< zp^Kucuw&2>%zEGeAlfhN^5n7q>YRV`!Q`3z`tL4o9@o$OIqTmNU(fUzwH@dY^gHwf zO4ySL9~4&nN#SFR3vlJn~1dKpn-Aq-nmZSqkoGy_e=U4SpJ&VbnmB9 zsY`qw@n^NV*A7+Cu%1-(dHP^Au=04OFNas&B=RqB$eE0tF5BsJA^A9$DJOIGd?9(y z&dw+EnaV=BbT^mHlpg8%cliwTCssFTnfd)G*gP}tx7zkrfdB8ztVQ1``p6Fe`ElkYGJ{wQ%1d?-8t z{vn(Ie-)kte-pOAQ_?35*8PnR(L1S`03#JiqC@mv;>J;2Z-V*zv&@`ee|@BD;G*>Z E2d^7$O#lD@ literal 0 HcmV?d00001 diff --git a/Sources/SKProduct+LocalizedPrice.swift b/Sources/SKProduct+LocalizedPrice.swift new file mode 100644 index 0000000000000000000000000000000000000000..2eaaa49459dd359c720580b1fd524aff4e711289 GIT binary patch literal 980 zcmZ9KJ#W)s5XaAbL9K+4n^tWF2rOVhG$hSiO@%~40zzt$D%^Ic#E?2}>o&xkcA!QI>0E5VGymgyr9(&MSi2YtHvc)QSN@jYlegQ z0~PFDki2u?Z-vjCPzC%(qANPSv=XS=z8l_JR&KTKKlf@Yf$w^^TYP}%GS{6W;$bc5 z9JB~s7OlaKK}Rs_I|l&Ke&L8GkNxd4{>{6Sr}DeMJGgmVKlA6bKPSGP=@V+(&@S{l z^aM)SlL_S+cz31F6X)Z%4VvW?x+4|I)#yz`+H%mqxO(qgr|;3fMV$L3{S7RC%ddNj zsZ{DbpGW+0)%Ba9YVBB$D*8OVw|20~c&5+C7hfjwPjASXjGZpq>2x9aAeSj8bM`_Z zdB@H!B=ecd!*Xdpm(7&!>-mrP4D=^fH)xsp{VCWyGwxSw`kTQ2cV^b2?-YIJdk~#~ zokE|#yaC> zLc~Lx&@0ecXkD}kI|d!W%x@h4MEm6}zCq$Y{?ETOGjS-t_N$8xB=wWO5Brw*dZzcN z{RI6C{RaIB9mBq+pgaTbu+qKf?0k9jY6`A_?nuRQCjJtUwj4AtuHHY_>3j5Vk>q|z ze*=%O;%|62vf1o0K9Bg_hU>Q@6|S0dHGQ78%~h;2nd#&1spsj^!}D?`Z|ACZE?2g0 z7xPuCXit}|>vmzgYgYY=`KsXKF7oGrr6*j>c>5~KN{>C2BYpEFrBNa<}k7!%s#(q+t0`vQ` POdeo=eWbJCIqClwG2w6U literal 0 HcmV?d00001 diff --git a/Sources/SwiftyStoreKit+Types.swift b/Sources/SwiftyStoreKit+Types.swift new file mode 100644 index 0000000000000000000000000000000000000000..6116dafadb382bcf9e797212a64a5c4d2e3a9b40 GIT binary patch literal 976 zcmZvaO-~bH5XWbEF`6`HDMk!w;zqa_EM5D?YDjEtF(gPrSn%edz#Gw)42fILYk%=H;24XLeUSZ;K$+N~@iTmREhq!uE3=U=T*rh?ae)?sr3>U#)CVR$o+| zTF{%{@#p{Z~ygI*;X!O7FiKWK2<4^irOqAf7OGG@V0lfn)Kp%^)!Cr9i#&;IdmPY++nZ~koK)=~Y)uZ#Yq_-dvmYCl3hLyw`~p}(Oq?1^XK zy%pPwcJriibOWx2?ns4lGkg<~vK-VfuG%@*se5#95#@eJe+`RYcb_}=Q>j#p&m%rx zS#@iH=WiIZWp$noj18f6x6zX(o9QU@;x7r+JKCGbn(VjfEbLX5mmdk*Byoezg=5*&q%J~)}OTPjz5~; zcD;>rlDD>_n*4A4dY8+lId_VP2h^e0p!3jW(FSZB8pV9CEC59Lr9GZD z^w<9Juil(EkzfDW$8E#<)UT8Nix2ODyqakrwLR#2=qKoB=r?E-`{5aQUuJ)$zGcRL zoQJES8>v7p1Sb(G%Rvp}q9xch*Qt99ZxQCc%lR4>-gGwYxlAT=mirOESF1Z6-|e>a zg^KE@*LusB^MaWUdsEMn#mASWCud~KMmAeY-zntE>4Gs+O3xbknRGE%xmz}G6!JOq zwwiyBd!S#ix>3u_-_O8K3E#J>E6eIJEH>~WoTg)YOZHB9m)>cjBG+RdjgGSl{JSG& zC29x3qqqf830NK9{XG~Acm|dflwb5NJCGQ7Qj!Vqg77@p5PksO60VN$LvTyt5uNCY z{BJSvONl4IZ-mFe$HGbQTj2@tk+2Sq%Q;!FI$t{=dMY*JV59;`9uPg3xb`uuPk{No Vu%y0Xe?z2;%yNDqLc5QI{{W;5bZ7to literal 0 HcmV?d00001 From 1213f2d524d5c6b4a7bada95d9bbe21687ad8617 Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Fri, 26 Jun 2020 17:10:21 +0200 Subject: [PATCH 7/9] fix sources --- .../AppleReceiptValidator.swift | Bin .../CompleteTransactionsController.swift | Bin .../InAppProductQueryRequest.swift | Bin Sources/{ => SwiftyStoreKit}/InAppReceipt.swift | Bin .../InAppReceiptRefreshRequest.swift | Bin .../InAppReceiptVerificator.swift | Bin Sources/{ => SwiftyStoreKit}/OS.swift | Bin .../PaymentQueueController.swift | Bin .../{ => SwiftyStoreKit}/PaymentsController.swift | Bin .../ProductsInfoController.swift | Bin .../RestorePurchasesController.swift | Bin .../SKProduct+LocalizedPrice.swift | Bin .../SKProductDiscount+LocalizedPrice.swift | Bin .../{ => SwiftyStoreKit}/SwiftyStoreKit+Types.swift | Bin Sources/{ => SwiftyStoreKit}/SwiftyStoreKit.swift | Bin 15 files changed, 0 insertions(+), 0 deletions(-) rename Sources/{ => SwiftyStoreKit}/AppleReceiptValidator.swift (100%) rename Sources/{ => SwiftyStoreKit}/CompleteTransactionsController.swift (100%) rename Sources/{ => SwiftyStoreKit}/InAppProductQueryRequest.swift (100%) rename Sources/{ => SwiftyStoreKit}/InAppReceipt.swift (100%) rename Sources/{ => SwiftyStoreKit}/InAppReceiptRefreshRequest.swift (100%) rename Sources/{ => SwiftyStoreKit}/InAppReceiptVerificator.swift (100%) rename Sources/{ => SwiftyStoreKit}/OS.swift (100%) rename Sources/{ => SwiftyStoreKit}/PaymentQueueController.swift (100%) rename Sources/{ => SwiftyStoreKit}/PaymentsController.swift (100%) rename Sources/{ => SwiftyStoreKit}/ProductsInfoController.swift (100%) rename Sources/{ => SwiftyStoreKit}/RestorePurchasesController.swift (100%) rename Sources/{ => SwiftyStoreKit}/SKProduct+LocalizedPrice.swift (100%) rename Sources/{ => SwiftyStoreKit}/SKProductDiscount+LocalizedPrice.swift (100%) rename Sources/{ => SwiftyStoreKit}/SwiftyStoreKit+Types.swift (100%) rename Sources/{ => SwiftyStoreKit}/SwiftyStoreKit.swift (100%) diff --git a/Sources/AppleReceiptValidator.swift b/Sources/SwiftyStoreKit/AppleReceiptValidator.swift similarity index 100% rename from Sources/AppleReceiptValidator.swift rename to Sources/SwiftyStoreKit/AppleReceiptValidator.swift diff --git a/Sources/CompleteTransactionsController.swift b/Sources/SwiftyStoreKit/CompleteTransactionsController.swift similarity index 100% rename from Sources/CompleteTransactionsController.swift rename to Sources/SwiftyStoreKit/CompleteTransactionsController.swift diff --git a/Sources/InAppProductQueryRequest.swift b/Sources/SwiftyStoreKit/InAppProductQueryRequest.swift similarity index 100% rename from Sources/InAppProductQueryRequest.swift rename to Sources/SwiftyStoreKit/InAppProductQueryRequest.swift diff --git a/Sources/InAppReceipt.swift b/Sources/SwiftyStoreKit/InAppReceipt.swift similarity index 100% rename from Sources/InAppReceipt.swift rename to Sources/SwiftyStoreKit/InAppReceipt.swift diff --git a/Sources/InAppReceiptRefreshRequest.swift b/Sources/SwiftyStoreKit/InAppReceiptRefreshRequest.swift similarity index 100% rename from Sources/InAppReceiptRefreshRequest.swift rename to Sources/SwiftyStoreKit/InAppReceiptRefreshRequest.swift diff --git a/Sources/InAppReceiptVerificator.swift b/Sources/SwiftyStoreKit/InAppReceiptVerificator.swift similarity index 100% rename from Sources/InAppReceiptVerificator.swift rename to Sources/SwiftyStoreKit/InAppReceiptVerificator.swift diff --git a/Sources/OS.swift b/Sources/SwiftyStoreKit/OS.swift similarity index 100% rename from Sources/OS.swift rename to Sources/SwiftyStoreKit/OS.swift diff --git a/Sources/PaymentQueueController.swift b/Sources/SwiftyStoreKit/PaymentQueueController.swift similarity index 100% rename from Sources/PaymentQueueController.swift rename to Sources/SwiftyStoreKit/PaymentQueueController.swift diff --git a/Sources/PaymentsController.swift b/Sources/SwiftyStoreKit/PaymentsController.swift similarity index 100% rename from Sources/PaymentsController.swift rename to Sources/SwiftyStoreKit/PaymentsController.swift diff --git a/Sources/ProductsInfoController.swift b/Sources/SwiftyStoreKit/ProductsInfoController.swift similarity index 100% rename from Sources/ProductsInfoController.swift rename to Sources/SwiftyStoreKit/ProductsInfoController.swift diff --git a/Sources/RestorePurchasesController.swift b/Sources/SwiftyStoreKit/RestorePurchasesController.swift similarity index 100% rename from Sources/RestorePurchasesController.swift rename to Sources/SwiftyStoreKit/RestorePurchasesController.swift diff --git a/Sources/SKProduct+LocalizedPrice.swift b/Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift similarity index 100% rename from Sources/SKProduct+LocalizedPrice.swift rename to Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift diff --git a/Sources/SKProductDiscount+LocalizedPrice.swift b/Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift similarity index 100% rename from Sources/SKProductDiscount+LocalizedPrice.swift rename to Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift diff --git a/Sources/SwiftyStoreKit+Types.swift b/Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift similarity index 100% rename from Sources/SwiftyStoreKit+Types.swift rename to Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift diff --git a/Sources/SwiftyStoreKit.swift b/Sources/SwiftyStoreKit/SwiftyStoreKit.swift similarity index 100% rename from Sources/SwiftyStoreKit.swift rename to Sources/SwiftyStoreKit/SwiftyStoreKit.swift From a1657e0c93389fde0f32a1868321c40824872030 Mon Sep 17 00:00:00 2001 From: Mario Hahn Date: Fri, 26 Jun 2020 17:39:06 +0200 Subject: [PATCH 8/9] fixed linking files --- .../AppleReceiptValidator.swift | Bin 976 -> 5081 bytes .../CompleteTransactionsController.swift | Bin 984 -> 3125 bytes .../InAppProductQueryRequest.swift | Bin 980 -> 2840 bytes Sources/SwiftyStoreKit/InAppReceipt.swift | Bin 968 -> 12519 bytes .../InAppReceiptRefreshRequest.swift | Bin 980 -> 3184 bytes .../InAppReceiptVerificator.swift | Bin 980 -> 5051 bytes Sources/SwiftyStoreKit/OS.swift | Bin 1016 -> 1913 bytes .../PaymentQueueController.swift | Bin 1036 -> 10781 bytes .../SwiftyStoreKit/PaymentsController.swift | Bin 972 -> 5294 bytes .../SwiftyStoreKit}/Platforms/Info-iOS.plist | 0 .../Platforms/Info-macOS.plist | 0 .../SwiftyStoreKit}/Platforms/Info-tvOS.plist | 0 .../Platforms/Info-watchOS.plist | 0 .../Platforms/SwiftyStoreKit-iOS.h | 0 .../Platforms/SwiftyStoreKit-macOS.h | 0 .../Platforms/SwiftyStoreKit-tvOS.h | 0 .../Platforms/SwiftyStoreKit-watchOS.h | 0 .../ProductsInfoController.swift | Bin 976 -> 3398 bytes .../RestorePurchasesController.swift | Bin 980 -> 4065 bytes .../SKProduct+LocalizedPrice.swift | Bin 980 -> 2815 bytes .../SKProductDiscount+LocalizedPrice.swift | Bin 988 -> 3061 bytes .../SwiftyStoreKit/SwiftyStoreKit+Types.swift | Bin 976 -> 15984 bytes Sources/SwiftyStoreKit/SwiftyStoreKit.swift | Bin 1028 -> 17552 bytes SwiftyStoreKit.xcodeproj/project.pbxproj | 518 ++++++++++-------- .../xcschemes/SwiftyStoreKit_watchOS.xcscheme | 4 +- SwiftyStoreKit/AppleReceiptValidator.swift | 127 ----- .../CompleteTransactionsController.swift | 77 --- SwiftyStoreKit/InAppProductQueryRequest.swift | 81 --- SwiftyStoreKit/InAppReceipt.swift | 285 ---------- .../InAppReceiptRefreshRequest.swift | 85 --- SwiftyStoreKit/InAppReceiptVerificator.swift | 119 ---- SwiftyStoreKit/OS.swift | 56 -- SwiftyStoreKit/PaymentQueueController.swift | 261 --------- SwiftyStoreKit/PaymentsController.swift | 144 ----- SwiftyStoreKit/ProductsInfoController.swift | 78 --- .../RestorePurchasesController.swift | 108 ---- SwiftyStoreKit/SKProduct+LocalizedPrice.swift | 61 --- .../SKProductDiscount+LocalizedPrice.swift | 63 --- SwiftyStoreKit/SwiftyStoreKit+Types.swift | 332 ----------- SwiftyStoreKit/SwiftyStoreKit.swift | 312 ----------- .../CompleteTransactionsControllerTests.swift | 0 .../InAppReceiptTests.swift | 0 .../InAppReceiptVerificatorTests.swift | 0 .../SwiftyStoreKitTests}/Info.plist | 0 .../PaymentQueueControllerTests.swift | 0 .../PaymentQueueSpy.swift | 0 .../PaymentTransactionObserverFake.swift | 0 .../PaymentsControllerTests.swift | 0 .../ProductsInfoControllerTests.swift | 0 .../RestorePurchasesControllerTests.swift | 0 .../TestPaymentTransaction.swift | 0 .../SwiftyStoreKitTests}/TestProduct.swift | 0 52 files changed, 291 insertions(+), 2420 deletions(-) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/Info-iOS.plist (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/Info-macOS.plist (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/Info-tvOS.plist (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/Info-watchOS.plist (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/SwiftyStoreKit-iOS.h (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/SwiftyStoreKit-macOS.h (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/SwiftyStoreKit-tvOS.h (100%) rename {SwiftyStoreKit => Sources/SwiftyStoreKit}/Platforms/SwiftyStoreKit-watchOS.h (100%) delete mode 100644 SwiftyStoreKit/AppleReceiptValidator.swift delete mode 100644 SwiftyStoreKit/CompleteTransactionsController.swift delete mode 100644 SwiftyStoreKit/InAppProductQueryRequest.swift delete mode 100644 SwiftyStoreKit/InAppReceipt.swift delete mode 100644 SwiftyStoreKit/InAppReceiptRefreshRequest.swift delete mode 100644 SwiftyStoreKit/InAppReceiptVerificator.swift delete mode 100644 SwiftyStoreKit/OS.swift delete mode 100644 SwiftyStoreKit/PaymentQueueController.swift delete mode 100644 SwiftyStoreKit/PaymentsController.swift delete mode 100644 SwiftyStoreKit/ProductsInfoController.swift delete mode 100644 SwiftyStoreKit/RestorePurchasesController.swift delete mode 100644 SwiftyStoreKit/SKProduct+LocalizedPrice.swift delete mode 100644 SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift delete mode 100644 SwiftyStoreKit/SwiftyStoreKit+Types.swift delete mode 100644 SwiftyStoreKit/SwiftyStoreKit.swift rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/CompleteTransactionsControllerTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/InAppReceiptTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/InAppReceiptVerificatorTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/Info.plist (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/PaymentQueueControllerTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/PaymentQueueSpy.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/PaymentTransactionObserverFake.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/PaymentsControllerTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/ProductsInfoControllerTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/RestorePurchasesControllerTests.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/TestPaymentTransaction.swift (100%) rename {SwiftyStoreKitTests => Tests/SwiftyStoreKitTests}/TestProduct.swift (100%) diff --git a/Sources/SwiftyStoreKit/AppleReceiptValidator.swift b/Sources/SwiftyStoreKit/AppleReceiptValidator.swift index 70fdf1f2d7593ee9ea94cb473cf31696d7ae71e3..b0432e21152082048c47355ce503d3bafc1008ce 100644 GIT binary patch literal 5081 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 DKH}}x literal 984 zcmZ9L&rcIk5Xav_F_0M27Qzo>!bTet6KhL!B;Xz?5F-%SOZTZwIvOD%D;R zf*RJLx1cl7N32V*{m=yZeQyCE%CBrw_p!fn!M`~@bS}U4yM^1w^`n2z`{V4Zo(@p^ z5qb*!3jGO9U{=FW>Vf80Z9TC*d^y=2gR5b8q#~J!P7*>{3TkK6|X$(X8S?-<3YY`IXIHLH`QVxf9p^}kJPpx-gNZc9w(=U~gkxZjfJE&~7GnOKRs zQ}oF9ASwY%^ZVOww`ot35h#7JZzB)iBsjy#B={Ng40w)t9{ielp^Kk_UvRuf$A5y~ zp%1*z@g(?=IR*a4oCbel9s-{+>)MtK6sC2iG873z(ygH5mkHnmOCJXOYC!?wmtch`xySNZqOti2Ei zo{FM?$1`WnnVB8?_I7Z43qkE34y#7yyG*f_6h)KknEl%@rN`=xmztas`f*IOknE9@ zg^W{iI7+_VX&B}s`1!}5eg(HKB+KBQfBPo17BJl4uit+8y4`2I8s}m^>S9++?zvK2 z)W8+&m}HwHY-Lt!Rya^f#z2&SoaB}{fJj+=gaeZb1H?vWyyo>5GRTnwaY1LjLnI|i z{gz3F{sm-8iJWH$35Cd;J*#!5DP_qkreLUd3~rJx;$~#>6fCOhS33s^PUxFP zqo*Qc&T5K6HMc^7VwE9>ARGl4(PxgvjS^vVj#jft^9=u`+S zpUL|-%Qaa@LMf_ByphIS)CDKuYSMKv#rxStyfP!JorPLxWNqqiI%3GQo$hX_T~<}F zVO{w!Ij^ZiWVOmrYqL=r=YeMx9E3D^KPw(v9&;a(XqG;^u@6B4t2lZJJl}&GH^J*0 z2cCm;9<5VAkJt^<7l>xyhA;3Kgq{QbpR3qU5{P2r5iD1Wz(;csP8Vx02p`}cL&GSA zMX(G~#7!eeF=vMs_!v5ar5{h{2=3koiy(b*2x}IkAtBGA7+hGnaT-k53pa+0jnqt#0sJj_#=M+?tKQKpbO;5Xgum&z2@U&wa8|Ru})KX%K~^XBvfRjF%3|jnh-~ zbCCEBxN(qBWoB`-G)k$u7=$?x2SY=@1)|EEVx1ayfVs<({5^W6o)VYfokN%yV) zcrf65ngBTMpMgFe@SO5Yb?d9Qwx&2pn=JnazQ8bMc%IlRi#^pN2@pnr?r zZr+yq9}SboQ}!^4HgpDY1kHBt$#Woi>{6&M!ebTN;+{johTuW+SGug2hPcq zmg*u(woib`Wv(_u!EgiXu0T|zE?`_(Dqo=HmBD>C|H*%dg`($6P$)!Z`u7C8Q*ZBZ zEuL6@Wh&1Ov~R9xw|qxdDW%4(SdJ|KHr@U-X+LnoTNjl(Gs1@hFF8J8CNvWr%eLPp zNrQ`QY($)mS40z;PPO^^I6PO%^>M7)I+*}FTvsCOt&d6Y#4O$T@k+PsWSqHl;_T=Q z|FW&S5={@JB4#<`xZ?52cfj4x`hKmg*AJRH*`2$hn>R(pr-s|ny&GD*v1N3wDj2JQemzv_DPx&nib3u5- zfIk1DDxX@2uS^%Jdk1@n9$gX4*QpGY-w?5@%9P|YBbrUKw@Ft`3>bceq0v hHpVy2dYq{v?(DM*rR%K;8XxmOI8~!Peebx={{z!^mQ?@% literal 980 zcmZ9KO-~bH5XWbEF_;*#Ed&TLvQaN4*4DnU8WX#=8jYGD3*J1Gc7X-j#ocWPi6(OM z;0NFUi3g7!IPd{#Pae7H$$0c87cZJn{Evao|(2N;IYG@`}8@q=C{@*CAP@1o=?Uai$|nqhx_ z%k$SqC2w!J%i*>idOp9A=!(RjG_B3eIp3?dYT=8P<8RM9uUk$K-U|2t(Pgf?K*Ylu z(3{W_^qFWKb_6zf{_}6#8#|X@``f|Ie=lyB%)l3JdZ9|Ws zKcUA^!k%;}&%nF0I`j7DAKwn9IEC&=MKTk;iAY%vY8Y4To$J&+dbfykf26;LgQbk%#{gY)DcEF9?^w72yT&8{x%1ehCgGK41{#50ds=wAIdM`BzFjA2u+eEt(*N)mgkQ Hm!$tGDS>SH diff --git a/Sources/SwiftyStoreKit/InAppReceipt.swift b/Sources/SwiftyStoreKit/InAppReceipt.swift index 4fa0ce8cc5a2d3bca5ed1c8c6ae9a34bad1ed942..a31b23a209f754b29e92bae7243ffe6c4d5041b5 100644 GIT binary patch literal 12519 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 literal 968 zcmZ9KKTH#G6vy8|YcL_CEk=xxZ~+HREUo>=VMyR?H5g^##Eqep!yedP(;gut7-eT* zWFcX2aByT`V1UNafx*!@8CM-((S-7S*Z1=ZFL`~R_viQS{ob#OuDeQ*O0n)+1I)V9 z&CyVVf9)5JcYYX6k6KNWeHO0^S=er_1B78TjcC4M*BkAS?^lW|?oG)R+|pXbu6mvM zb+^9SCwXh#S@t$8&#m(piDD9eUNvjAIlE*#HE*oJMMOiKyFtVQ>d=SKY3NJQCDoM@zqQpQF{RW0{sU42|a^`upgd* z_hmNctj|Awy}tujLwBTn8TP+Kq$~$DjEf`wuDMR#qkW4YcP{-kEPUB{Yd=mT61{vL z@!4X@sd{dstj`qGdD_>@SYJyc_W$3#h+$U`FO?{&&4N<^msg* zDm=@Zk22|$`9#gX#b=JIW|?unrK+_Ea`u3?FQXN0H0hVUzJO?bY8UxUjM@6w6x%R7X@yAqFpKM6;{--Tn~ zBjJAVS79C8BYl!!)n7X%+LW3o7%5+3$3)u_*G_}_2$9A`x=01F;4w{oqGQpittp)N}C zUb4tYC#8tBNNIIP`>ou?8$m@*uYMZ6d^LLcddNDHVt-f4%~n%C8PKaAU%nw@|#JpJ!MJm_)Uzqsz)hd%}Yf&m0eN|~_Di$UpXDdWADoRo!Gvojw5r7H$z|p9& zBjgDznsh0a+-{5A<9MWDwXVt>j!|bQr3KPw{Qe;l%@Ph_U1V8t%P}TJo=Of}jhiY) z_#Ur{8)3q#dm%40SeyKtiWo9=rJGM`8)q473Ye{iSHluqmr?ry3x6R5fL;3+l#KrpONid(|gyO zTI5_U11Aj04;al|Ea$ERvFlCd7gN`JM`tkg{D|i6!i|6%`Nn61<~lH)(ZUHP=K#0Q z+_@WFTZ}bxBae}1en2)Y?I3a|7jrwHcp0WTDu z+w(blV>tT)VFXN+CjRm|aNnIrbnefm4uoe8_}OQ3r}l>ECUe_eSTwa4_B-YnkPjde zBx}|*>GIrRDSNf?H;G)|<9H^%7X^5=5N;4XSYNuKW04)WA!lY5_zM#$XBS5B0UVfm zP7TDFe_SA_aKSDReancZjy(q)s^vW`=&;w5JMI8_*ip^ZLYH2f+~zR(-$AKVP+hhOPKAyZ@9HR`T$w)q{) z$jFvufhp5i31j*gVu9qFF;?;2=TnP*2ie-qnBEGN#Csm)Ck%|w=MRgTf1TlVl_&6P z&XVt80HV3fu=oBqi%$MC!Hc*q)|<9=-Sjl^^^YXz8&Q{A%d##Um%4E?#4ajzzbn_+ zo$cptoojN0RL7?Aj?gsLY}UFTKP^yQfmGnw)15ptb$B@8jhkWGbakEjE;Tkk zmXpU#^Pfs~7z!Lt>tP!KFxp2$fKzD{j#7p;&*YKR9Ao=U1rJqG6$W8w!t4l{*ipaT zR5815u1uphRqv$y`5+#(NHg;WB#HAxWc|VSp|si!7fzgcYzEJicq-Ewf>c{Gft}_u zk6lNj7jjK?M=D(Knz=x}+wqCj>2ta7@NFPWfezcoz;s}d|;bKeQ9=vBz}(dMjVb%t(^_0Y4iP-bS=6U|cn$HvSFzCjC{M_K|A`{Qk!1-+8gNrvwdw_NOVk*@> l*2(s_N>pOVWQVc3!)osopdHzEkTHu4b*Ms}&->ne?;l?p_`LuC literal 980 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 literal 1016 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 diff --git a/Sources/SwiftyStoreKit/PaymentsController.swift b/Sources/SwiftyStoreKit/PaymentsController.swift index 7764dff238e5740e1f619add418eced9e8153579..b57c81d747a9d1baa2b79d5a443a1cb62caefce2 100644 GIT binary patch literal 5294 zcmeHLZExE+68@fFF%9;EeDEqwued!J$YvE=X@oeoPgdG3dc{JP=$Kbo@`+N?bkYC5 z&rqZ!=cU^N?%Q1v)Dk(Imxs^HkUBa#I69(5e7_ZWrN%{Gl|`0`(p7hIUGdzKAMTe` zQHo2+BRn`RcK4;c*;M2t1A6uH_$Tu6v=lL&$uD1usw&7?;py+Mf4SMlGINt+J1}b( zqTEWQWRa6pv=OCP-P27O=aoo@v@V69Vok{=E^ow;pefGpX(vjB1;wh0WiIm@iYb8) z>kib|oXQYNfs2%#jaQ})D8XL2iz5nit0QLGOk)C!@n!$aB@sa*4~(DCi+ zRVLMDNU3D)tGa@u;=x4Zyb94A6(uQ=Y3HCsA^;t9=c5*5L%<1M7`POV+--{Oemqip zwXVw?h5-pxbSH?Kabvdp-;h* z7UBGDF!3jJ=q>SnIHY$$bTPk<2oj+;i{8`xoV?k4x(sHMA^E>9LVvlWdB}bQSBq)j zV>pK=_vlVz)ykYsasZDD!wL-~-z3DJqmj!XnpTV1I)YEkv%RC<$tz$4=PaPC)zd_2BElfiCU|?Gw~;sz*=M ze#1L2zn`zT1~-h;s(y)Y(L$Ngj+`&)_?7z#{pz-ToG*W+G=7*2_lA0K6 znWsi3$W!sz;T~=ZL${A4+da2At2u+jKkad5jqYr0BWU}m(0FmQv9FdT_P1vRbm|QC z^fID`k2W-SElX83E*I;ORo>-IlL)<)9mpClTNX_4&Tm#lnl52 zxpR9@2}p$_vdrTwdPc&v0z=A$NYy#&r`qgEzp&<>>aL7KyKDSnh3%oi>ELrLSjbg_ z)nL%U&#SQoRzYX&0qi|1IyF$89{B9^@aT#Zuj_c#)1ur`Y;mP_hUPU*(l^c%6&SJM>-5w}L(IaTn^U{6G6~J>t>e@Bx-Oa}3V^ zYxHb)rMJ!Q|0&7E5Cv_G`lJc@ConZ~jws6lhxi^XeI9YZ&Am}q3*s9H&6Zl?bnr00 zO?Lgqd281FcQW-+$H9@Ad7@7#Pen-vfi^6@^eiuRjJ@K-3AaV(k8il=Ahkc`#a-Sk zK5U_8sW_{e#U~ajCoS;7D(AC-o|))Z{&qezp#&>Vytj1>=eBmjBd|lx5 z302bq9G722IuR-<<&HmLTnbzcty>?vlE!}I%DN$VN9pvmb*=T+pk-Weelu%EcJcQd zfYkm82v?&I?V&&FI@8DRIRrhuvVW>*3w3)}Rp=2}g*(*m^x}!**$=p(6u`dE&VlI_ Hd`1GDp)A8&Tv?5;?;Eg+?Wr>q4gJ#D3E zTZo>{d)HrD7)p-XwJiB0do9Sqwo)CS9mX((Sgbf+r4dqosjwxxIG2~JJ0+*=H|KYy zx81{ed)Hm}_ibN#^hO~DIsUP*ua4zp+4p3z=y-1`R60!g4k2hr6Z#rD1D$7GgYAU2 zVa9VC0MUNth$asFjc5L=slF%qtv@x~IH-^Oed?R+>zOW5`vv+9dJFvl{SEEJj%Wtj zS+=%dU)@FS)jiQ2DJ3K7O+si(K?CFJeN!FvpnElL5#)Yxe*;TjcZ<$sEEemg^N4>a zth!}iRyNJKygn~3%uTF1nCa{F&_Ou8{F2Wkta#3f$1~BlsYEWCvc@yf2`f1sO(*j2 za@ny|GLfCt^B>U}=mS>QY>DapG1xRQ?zdKUSAdUqCf1_wq(1UAL?>YT(dS>iUZ|5crC@7yO+$46ZWw xfp3^ia5wjfgLQwSD#Rhz^n#I660Qny!g1p!s1JeZ`;$a|Vt)-3FTfV}{|^QWY5xEK diff --git a/SwiftyStoreKit/Platforms/Info-iOS.plist b/Sources/SwiftyStoreKit/Platforms/Info-iOS.plist similarity index 100% rename from SwiftyStoreKit/Platforms/Info-iOS.plist rename to Sources/SwiftyStoreKit/Platforms/Info-iOS.plist diff --git a/SwiftyStoreKit/Platforms/Info-macOS.plist b/Sources/SwiftyStoreKit/Platforms/Info-macOS.plist similarity index 100% rename from SwiftyStoreKit/Platforms/Info-macOS.plist rename to Sources/SwiftyStoreKit/Platforms/Info-macOS.plist diff --git a/SwiftyStoreKit/Platforms/Info-tvOS.plist b/Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist similarity index 100% rename from SwiftyStoreKit/Platforms/Info-tvOS.plist rename to Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist diff --git a/SwiftyStoreKit/Platforms/Info-watchOS.plist b/Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist similarity index 100% rename from SwiftyStoreKit/Platforms/Info-watchOS.plist rename to Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist diff --git a/SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h b/Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h similarity index 100% rename from SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h rename to Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h diff --git a/SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h b/Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h similarity index 100% rename from SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h rename to Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h diff --git a/SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h b/Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h similarity index 100% rename from SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h rename to Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h diff --git a/SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h b/Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h similarity index 100% rename from SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h rename to Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h diff --git a/Sources/SwiftyStoreKit/ProductsInfoController.swift b/Sources/SwiftyStoreKit/ProductsInfoController.swift index 10366539496e530b84f8660216312ea0e60577d4..591e26a14dfac85fdd523e143937ad44c2823ad0 100644 GIT binary patch literal 3398 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 M{)_N)>+zNBZ=ZW4wg3PC literal 980 zcmZ9KO-~bH5XWbEF_;*#6aq#`*r*qywY6`o#>CcEVj?DnrQST0ve<>TPqMp&NHCF` z2R?uYNIZD-;DHZNd-BN98y>yM#RHmH|FfOPEle^yzj=9P=b7CVr8WrCs`-(%!L0kk z933(F=|1(s-uBh(b*EcmpXKckvarKk2N;Dh45Dh_`awSw`K{Wzx+uAds&BU3b~u>d zQvSxcVEqv{S%I7x{SrT7z1CBl4^y`gU;09&Y4t>>Zy8fMjkIZu21tK1n&)kL< zp^Kucuw&2>%zEGeAlfhN^5n7q>YRV`!Q`3z`tL4o9@o$OIqTmNU(fUzwH@dY^gHwf zO4ySL9~4&nN#SFR3vlJn~1dKpn-Aq-nmZSqkoGy_e=U4SpJ&VbnmB9 zsY`qw@n^NV*A7+Cu%1-(dHP^Au=04OFNas&B=RqB$eE0tF5BsJA^A9$DJOIGd?9(y z&dw+EnaV=BbT^mHlpg8%cliwTCssFTnfd)G*gP}tx7zkrfdB8ztVQ1``p6Fe`ElkYGJ{wQ%1d?-8t z{vn(Ie-)kte-pOAQ_?35*8PnR(L1S`03#JiqC@mv;>J;2Z-V*zv&@`ee|@BD;G*>Z E2d^7$O#lD@ diff --git a/Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift b/Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift index 2eaaa49459dd359c720580b1fd524aff4e711289..693db5240631ecd45a58d651816ae945a8f3ac7e 100644 GIT binary patch literal 2815 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 CcHk)h literal 988 zcmZ9KO=uHQ5XWcxAr(Z@RBVx;i;5_^Cg!WF6l_eCLL(H{_M}3(+1hQJJlNe(6g?C? zh$jzTg&sWi*naC> zLc~Lx&@0ecXkD}kI|d!W%x@h4MEm6}zCq$Y{?ETOGjS-t_N$8xB=wWO5Brw*dZzcN z{RI6C{RaIB9mBq+pgaTbu+qKf?0k9jY6`A_?nuRQCjJtUwj4AtuHHY_>3j5Vk>q|z ze*=%O;%|62vf1o0K9Bg_hU>Q@6|S0dHGQ78%~h;2nd#&1spsj^!}D?`Z|ACZE?2g0 z7xPuCXit}|>vmzgYgYY=`KsXKF7oGrr6*j>c>5~KN{>C2BYpEFrBNa<}k7!%s#(q+t0`vQ` POdeo=eWbJCIqClwG2w6U diff --git a/Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift b/Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift index 6116dafadb382bcf9e797212a64a5c4d2e3a9b40..8eea5c9bb0f1b716a02ef2b333dd79a529425dc4 100644 GIT binary patch literal 15984 zcmeHO>vG#R7XH0{3QYRP&dQRV^tPU+scg%!8e7sxO480w$Du^XLQ9b0$jX zp3uXSWW7n%^)eH?^F8tC;P4~Sjl)z1;#mFgLy~2Q*q!0iryqWCy$V#+o+qn4yLTkh zmC{-zu~1qpWh!SIah(QnCc~Ckq*97xA?C{1}VijMDK+Hh{ z(SpU<5|DJV$ZmsFVtptAt&_P508)g>JYUH;3o=5vP?6MPH(N^aU}ASX*ke4Q3?c%k zVgQuFy%o1ATPArXQmM04%?V5ki{?=t5+&|+q*lrzq3tXlP4K`%uE7cs+!CuKR15km znZI>Di+~qBFG6;SaE53a=T1c zRelsxwaC*Lh#?>>3KNKr@qR1k89gBu7D*H(x5VQ-i9mz%LQ@jsm$&F;Tj4s4U z2C7;9d?HMYIcfV!FM}u&Gik*K)Sg! zYDF3#oOjxxC70dt^CL0JQ#c7NH9f;VD5QH7iglV~$vlZjvyxj4>sl<}X=0d$-6j_N z0;&#mT*AsCXd^rkJk<(*VxEMgr9y*%2ujX~2oEDWgGI_W0l(TLIacRUC{lO{3CqFX z>m`hcmhy6e{}y>X2N|KG@w3s9`xt({t1`Jd8tsW6MZ4V=KNmX}B_ac9f6HByX9avV5!>Xx;NnBW3wh&?5H)ail_L$Hhy*;%qf8etir066akxim z66W*J5Tx_@Tx!h(?Cr4Uo0li$V20wy9TM10kkU(R&-&pJG$18U^rN_z83g23e4mq} z$Tml!kHg)5o4_%tIEWnVQ$&O#LH{q7{=Bmz-(>K$6dl~UQo9^AmRcg}KA=n&(RQ5& zX((_oA|z~2ie270J#A;@p)pZUp9=3$?X`?F2rqCDo<)!aQ7=uCboT*#Ho~7qu!1rM z(QUBNq}+iIlgWXnCl60S(=3L2h7GLOGKTs+*efs?ITM~#W(XL9xAW_tcN!&kDiNV0 z{eJ*;>=W zr!8?GdGN+e9GxE0uSL6{4CY*Xt}bzuVukxyUEtAY{Gs1#y?fc|A2yUo+00sMOjHZ zb}e-+TQoi0GkbjiRxR#9*Lo)e4H~fpn>AwVS@n3E87lW}aat;X^?(^Vm+-`a785RO z;4&s8A?vu#xyVleZ}&>9jWhH7T1()mF;ISLKC%nuWVMFm#Tr3DhR$Q@3j8~~TH(>X zMuv6y;)Vi%nj06x-o6i?gDxD^-zE~lq)>&KMunCsb~ptqdAHzr?-RIGb{a?M&u)e@ z>h67GBFUM|=1UK7&1!f-B^)(bj-{-OZ+BUYg;X^g6Z7t)q9H2YL&g!RDV7v*|4x(` zlVo8dL(usun4#@MjgvtVmrtCy*{>MdoPAmdreH0_;&HuQQt+E9Bt5TOh6 zRxZ>Cou^1as5b%Y*mi7Y*~D9Q9})7+TBVyZ>ci)Q5^@+$X!!b#M;ULB;qE(c+-Av| z4hzkvmPQT!X$EmOq zMjNQRR=9Rd8BUUr&(|ClW1{SedWhBq2;_k_b#bj{k`}rqK_+hDVv56UV;edtARwn^ zc#3mcqg~F;cXVXLYYVZ=g`z1O2*4OkQKg!9956DX9fXK)kf=KmYnSu-iP) z0ctZ3miflc884`CiqJTdXlE^q9=robuC)Cl7;(6`!B=O(6U_TNG7l(A`?dF==@@I$ zudGKjVIN#2{tRxt+L>e3g7#3z(s;K{<&8>mC{o$)K-E~)h6bix-Rtjbi{j{u4?}=T zZxs!hjIz%$Z{f12qHi9Cx2bv)=3gd2(ZvMF#uCc4X}-6_sE@Q0ZF_ixNV9Ve@CsgH z-#jEAU2&4j023(^kq%bU+9U-~Zg!#$iNe}hIijbfl*@i|^~|OKOflb#xZrvK7w&-Y zv2%DQzu=u}O-AITOXI4M?0iq@%d2$$7Tse0?0C_Mrm9KzySt`6Z{rWWdx-SjgSEOr z`VVKTFpfl`1T!Jo&m@}sJQcQdS5yLyRweNHsL(KRreSeSXQ)k%m#kCrZVho^`Yy4P zdaP5m3et`EPHtFVZ5Y{5iC-nlCI`B9y0>yROhcJos95$9b4qRWsyi31I5u-IG@5CY zy~-hYe*WHxTH@f~i2sRa zml#p<`4fLQh=&i8INCgXNX|;rc#ZHsd{{M6ysohB?7YUgzp6*s3Nu!UdyD@&)SRqv zP7MJ&(d({xg2z1_#5GNvmbX<%wJZ54#F#=VdBPM-UP=HD(QPLjq^KxCYdFF)gva76PQDM_3~8@{Q) zuJu}xEg&e-fSt{wMvT%^dOhN|N21!UC*^w|guou-EKT6#F`T`dl75U7FHMHDs+l00 z_`Li4ptP;Vse%969c6hm<(9fH!QnPzM{y* zjKm?JJ2R=I^TCjmJ5nS%ZeLAsm2b**_M`nnfhve8quoVclv@H;9n5=sk%Q?rdVwnx zBn}3o8Ai!e9)A~OVgTjdf8=esTMFnU&~1$U!(uge6wC%sNzKzI;-FYZ*&R{|uz~sv zGN4Nq6nK#g;0_&LlD@g>oh}7IXK0#a^GQ~HI@>{#jj@H>5UkNOpaf?XL`bz($mkIN`95WQZGt!>DqauMOS)_sUz7EKal%(hig>a(JdWtj zNDlPqe^8R`Ghi2=5cgo@Sa$t|7XIUk%y8$AZXF@TgvtnCFt~Pz44!0&xeA(*#Bp`C zy|BqyC3d1>ogthub zTr9B&KJpL%p2L8TMt5+P({SXq=a2?!O2!o=(iX4C&vHFu)Y=#p!?JB&crj+%kZn>{ zhsfv&8U+z9^RR_bdXH4LuuR}u2e>?Et0H9R>}os~YrzU2jQBn-xHI{_!wTvasl8E( z`YRJMzENos)Af;-Af9pkloXV!0ozTmSq616z2$tWNQsN4cN!?I`Qj|{^k-W+PIMyPdr znXRG^IvqxEmC8j2cdm=5@ZjV9$*aSr1cTc649kT-+byQR zaGcYfO;PsaY-QTef`xd{n}r#ioS9waCK3wy9m3RJqY_35i+P%-VKc^arA$Ubn8|B` zC+=!MfBEL1DX815a=(NEwC;Hy-PBaW$sW0JM;)eDX=WFg)*;`Y98Sbndv$s}Qc2Ku zfOKUE^Na!gFpJbW1S|*dwx8`%Xw-==&xVWo6Zm2In;eu5#u39##UrvTp*i5WH&<_y z0oemG+g0hp5GkfGgTqktRbb8h}0|7iC*1m5 zucz&zMFey@6+=TE#JVi?<2Bqj!fK<@XtX z{DH#`kLxB8{n4Y2;xq~u=@GbnEEL+#XneTupnnEuzZRUva8YSBAT#O}bEqnLlN`z_HQ=PL5{x%>HcDvjdfa zQyYwbu{OQu@xl8X78E@Box&<(A7Ji~=v_`JfBK0&W;aMLD}k_!ZU_IErbu28?QLHJ zzf|O#3wf;2=0c{T%sq$=XURwwT!LvbN6wB=T2Q9unKypNw(u)gH*`VY0(V#x&0{=J zy2Wh)FhxI<1T0fSBV|V&Sp0H}e$9#LNp?%4I^bKisU3s*7u^{A+*4gsi9^|rcX5MK zEt}xmz`0d}mcN9tSsJwke1&sLB^;*~+;&Z9-G`~UK>s$J%V16{BPXP;7}xCe0;V`6 zPGYe9in0>lM}L3Rm0jpE7!zRBKspml$h(D3vsLdjbZAD740 zJcg66j7j)O@7OlA->B>aJxXpwK7M2?PQpM`Laz}b=sGxQ(t>{LL>fl58I5dki$P*P zkJ=z?+t-1p4?lTqrOWT_3y7EmVP>*=gXV_4VYGcR+&BvHGe7*im-L(uSY?&AlkEe; zEU57W9b6~qgPW$2g&kzTu*NnRmia9;h-7|>Du@FADnJp4E)VX$lhY;RhGC{0?$k7o fK`_jLj}e+&oFX4LSb9kULK6c#^ShsStlIt;d5BcQ literal 976 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 Vu%y0Xe?z2;%yNDqLc5QI{{W;5bZ7to diff --git a/SwiftyStoreKit.xcodeproj/project.pbxproj b/SwiftyStoreKit.xcodeproj/project.pbxproj index 56f1294c..90d958dc 100644 --- a/SwiftyStoreKit.xcodeproj/project.pbxproj +++ b/SwiftyStoreKit.xcodeproj/project.pbxproj @@ -7,29 +7,98 @@ objects = { /* Begin PBXBuildFile section */ - 1592CD501E27756500D321E6 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */; }; - 1592CD511E27756500D321E6 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */; }; - 1592CD521E27756500D321E6 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */; }; - 54B069921CF742D100BAFE38 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */; }; - 54B069931CF742D300BAFE38 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */; }; - 54B069941CF742D600BAFE38 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6231B98586A004E342D /* InAppProductQueryRequest.swift */; }; - 54B069961CF744DC00BAFE38 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C680F1C29414C00B60B7E /* OS.swift */; }; - 54C0D5681CF7428400F90BCE /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6241B98586A004E342D /* SwiftyStoreKit.swift */; }; - 6502F63B1B985CA1004E342D /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6231B98586A004E342D /* InAppProductQueryRequest.swift */; }; - 6502F63C1B985CA4004E342D /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6241B98586A004E342D /* SwiftyStoreKit.swift */; }; - 650307F21E3163AA001332A4 /* RestorePurchasesControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F11E3163AA001332A4 /* RestorePurchasesControllerTests.swift */; }; - 650307F41E3177EF001332A4 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F31E3177EF001332A4 /* RestorePurchasesController.swift */; }; - 650307F51E3177EF001332A4 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F31E3177EF001332A4 /* RestorePurchasesController.swift */; }; - 650307F61E3177EF001332A4 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F31E3177EF001332A4 /* RestorePurchasesController.swift */; }; - 650307F81E317BCF001332A4 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */; }; - 650307F91E317BCF001332A4 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */; }; - 650307FA1E317BCF001332A4 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */; }; - 650307FC1E33154F001332A4 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307FB1E33154F001332A4 /* ProductsInfoController.swift */; }; - 650307FD1E33154F001332A4 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307FB1E33154F001332A4 /* ProductsInfoController.swift */; }; - 650307FE1E33154F001332A4 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307FB1E33154F001332A4 /* ProductsInfoController.swift */; }; - 653722811DB8282600C8F944 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */; }; - 653722821DB8290A00C8F944 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */; }; - 653722831DB8290B00C8F944 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */; }; + 2F2B8B3024A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; }; + 2F2B8B3124A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; }; + 2F2B8B3224A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; }; + 2F2B8B3324A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; }; + 2F2B8B3424A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; }; + 2F2B8B3524A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; }; + 2F2B8B3624A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; }; + 2F2B8B3724A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; }; + 2F2B8B3824A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; }; + 2F2B8B3924A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; }; + 2F2B8B3A24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; }; + 2F2B8B3B24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; }; + 2F2B8B3C24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; }; + 2F2B8B3D24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; }; + 2F2B8B3E24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; }; + 2F2B8B3F24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; }; + 2F2B8B4024A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; }; + 2F2B8B4124A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; }; + 2F2B8B4224A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; }; + 2F2B8B4324A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; }; + 2F2B8B4424A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; }; + 2F2B8B4524A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; }; + 2F2B8B4624A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; }; + 2F2B8B4724A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; }; + 2F2B8B4824A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; }; + 2F2B8B4924A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; }; + 2F2B8B4A24A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; }; + 2F2B8B4B24A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; }; + 2F2B8B4C24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; }; + 2F2B8B4D24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; }; + 2F2B8B4E24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; }; + 2F2B8B4F24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; }; + 2F2B8B5024A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; }; + 2F2B8B5124A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; }; + 2F2B8B5224A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; }; + 2F2B8B5324A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; }; + 2F2B8B5424A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; }; + 2F2B8B5524A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; }; + 2F2B8B5624A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; }; + 2F2B8B5724A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; }; + 2F2B8B5824A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; }; + 2F2B8B5924A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; }; + 2F2B8B5A24A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; }; + 2F2B8B5B24A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; }; + 2F2B8B5C24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; }; + 2F2B8B5D24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; }; + 2F2B8B5E24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; }; + 2F2B8B5F24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; }; + 2F2B8B6024A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; }; + 2F2B8B6124A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; }; + 2F2B8B6224A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; }; + 2F2B8B6324A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; }; + 2F2B8B6424A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; }; + 2F2B8B6524A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; }; + 2F2B8B6624A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; }; + 2F2B8B6724A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; }; + 2F2B8B6824A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; }; + 2F2B8B6924A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; }; + 2F2B8B6A24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; }; + 2F2B8B6B24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; }; + 2F2B8B7424A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; }; + 2F2B8B7524A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; }; + 2F2B8B7624A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; }; + 2F2B8B7724A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; }; + 2F2B8B7924A64CD700CEF088 /* Info-macOS.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F2B8B6D24A64CD700CEF088 /* Info-macOS.plist */; }; + 2F2B8B7F24A64CD700CEF088 /* Info-watchOS.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F2B8B6E24A64CD700CEF088 /* Info-watchOS.plist */; }; + 2F2B8B8024A64CD700CEF088 /* Info-iOS.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F2B8B6F24A64CD700CEF088 /* Info-iOS.plist */; }; + 2F2B8B8424A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; }; + 2F2B8B8524A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; }; + 2F2B8B8624A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; }; + 2F2B8B8724A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; }; + 2F2B8B8824A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; }; + 2F2B8B8924A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; }; + 2F2B8B8A24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; }; + 2F2B8B8B24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; }; + 2F2B8B8C24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; }; + 2F2B8B8D24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; }; + 2F2B8B8E24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; }; + 2F2B8B8F24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; }; + 2F2B8B9224A64CD700CEF088 /* Info-tvOS.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F2B8B7324A64CD700CEF088 /* Info-tvOS.plist */; }; + 2F2B8BA024A64DE600CEF088 /* PaymentQueueControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9424A64DE600CEF088 /* PaymentQueueControllerTests.swift */; }; + 2F2B8BA124A64DE600CEF088 /* PaymentTransactionObserverFake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9524A64DE600CEF088 /* PaymentTransactionObserverFake.swift */; }; + 2F2B8BA224A64DE600CEF088 /* ProductsInfoControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9624A64DE600CEF088 /* ProductsInfoControllerTests.swift */; }; + 2F2B8BA324A64DE600CEF088 /* TestPaymentTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9724A64DE600CEF088 /* TestPaymentTransaction.swift */; }; + 2F2B8BA424A64DE600CEF088 /* TestProduct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9824A64DE600CEF088 /* TestProduct.swift */; }; + 2F2B8BA524A64DE600CEF088 /* RestorePurchasesControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9924A64DE600CEF088 /* RestorePurchasesControllerTests.swift */; }; + 2F2B8BA624A64DE600CEF088 /* CompleteTransactionsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9A24A64DE600CEF088 /* CompleteTransactionsControllerTests.swift */; }; + 2F2B8BA724A64DE600CEF088 /* InAppReceiptVerificatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9B24A64DE600CEF088 /* InAppReceiptVerificatorTests.swift */; }; + 2F2B8BA824A64DE600CEF088 /* InAppReceiptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9C24A64DE600CEF088 /* InAppReceiptTests.swift */; }; + 2F2B8BA924A64DE600CEF088 /* PaymentsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9D24A64DE600CEF088 /* PaymentsControllerTests.swift */; }; + 2F2B8BAA24A64DE600CEF088 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9E24A64DE600CEF088 /* Info.plist */; }; + 2F2B8BAB24A64DE600CEF088 /* PaymentQueueSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9F24A64DE600CEF088 /* PaymentQueueSpy.swift */; }; 654287F61E79F5A000F61800 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 654287F41E79F5A000F61800 /* Main.storyboard */; }; 654287F81E79F5A000F61800 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 654287F71E79F5A000F61800 /* Assets.xcassets */; }; 654287FD1E79F75000F61800 /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */; }; @@ -37,25 +106,7 @@ 654288021E7B34E500F61800 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF701DCD4DF000835D30 /* ViewController.swift */; }; 654288061E7B3A8800F61800 /* NetworkActivityIndicatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF6F1DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift */; }; 654288071E7B3E1500F61800 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF681DCD4DF000835D30 /* AppDelegate.swift */; }; - 658A08371E2EC24E0074A98F /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A08361E2EC24E0074A98F /* PaymentQueueController.swift */; }; - 658A08381E2EC24E0074A98F /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A08361E2EC24E0074A98F /* PaymentQueueController.swift */; }; - 658A08391E2EC24E0074A98F /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A08361E2EC24E0074A98F /* PaymentQueueController.swift */; }; 658A08431E2EC5120074A98F /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */; }; - 658A084A1E2EC5350074A98F /* PaymentQueueControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A08491E2EC5350074A98F /* PaymentQueueControllerTests.swift */; }; - 658A084C1E2EC5960074A98F /* PaymentQueueSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A084B1E2EC5960074A98F /* PaymentQueueSpy.swift */; }; - 65B8C9291EC0BE62009439D9 /* InAppReceiptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65B8C9281EC0BE62009439D9 /* InAppReceiptTests.swift */; }; - 65BB6CE81DDB018900218A0B /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */; }; - 65BB6CE91DDB018900218A0B /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */; }; - 65BB6CEA1DDB018900218A0B /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */; }; - 65BF8E301F4AEEBA00CBFC00 /* ProductsInfoControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BF8E2F1F4AEEBA00CBFC00 /* ProductsInfoControllerTests.swift */; }; - 65CEF0F41ECC80D9007DC3B6 /* InAppReceiptVerificatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65CEF0F31ECC80D9007DC3B6 /* InAppReceiptVerificatorTests.swift */; }; - 65E9E0791ECADF5E005CF7B4 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */; }; - 65E9E07A1ECADF5E005CF7B4 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */; }; - 65E9E07B1ECADF5E005CF7B4 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */; }; - 65F70AC71E2ECBB300BF040D /* PaymentTransactionObserverFake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70AC61E2ECBB300BF040D /* PaymentTransactionObserverFake.swift */; }; - 65F70AC91E2EDC3700BF040D /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70AC81E2EDC3700BF040D /* PaymentsController.swift */; }; - 65F70ACA1E2EDC3700BF040D /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70AC81E2EDC3700BF040D /* PaymentsController.swift */; }; - 65F70ACB1E2EDC3700BF040D /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70AC81E2EDC3700BF040D /* PaymentsController.swift */; }; 65F7DF711DCD4DF000835D30 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF681DCD4DF000835D30 /* AppDelegate.swift */; }; 65F7DF721DCD4DF000835D30 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF691DCD4DF000835D30 /* Assets.xcassets */; }; 65F7DF731DCD4DF000835D30 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF6A1DCD4DF000835D30 /* LaunchScreen.storyboard */; }; @@ -68,40 +119,6 @@ 65F7DF881DCD4FC500835D30 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF831DCD4FC500835D30 /* ViewController.swift */; }; 65F7DF8E1DCD524300835D30 /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */; }; 65F7DF8F1DCD524300835D30 /* SwiftyStoreKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 65F7DF9A1DCD536700835D30 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 65F7DF971DCD536100835D30 /* SwiftyStoreKit-iOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 65F7DF9B1DCD537800835D30 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 65F7DF981DCD536100835D30 /* SwiftyStoreKit-macOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 65F7DF9C1DCD537F00835D30 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 65F7DF991DCD536100835D30 /* SwiftyStoreKit-tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A61BF4BE2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61BF4BD2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift */; }; - A61BF4BF2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61BF4BD2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift */; }; - A61BF4C02481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61BF4BD2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift */; }; - A61BF4C62481F4970017D9BC /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C680F1C29414C00B60B7E /* OS.swift */; }; - A61BF4C72481F4970017D9BC /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */; }; - A61BF4C82481F4970017D9BC /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6231B98586A004E342D /* InAppProductQueryRequest.swift */; }; - A61BF4C92481F4970017D9BC /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */; }; - A61BF4CA2481F4970017D9BC /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70AC81E2EDC3700BF040D /* PaymentsController.swift */; }; - A61BF4CB2481F4970017D9BC /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307FB1E33154F001332A4 /* ProductsInfoController.swift */; }; - A61BF4CC2481F4970017D9BC /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F31E3177EF001332A4 /* RestorePurchasesController.swift */; }; - A61BF4CD2481F4970017D9BC /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A08361E2EC24E0074A98F /* PaymentQueueController.swift */; }; - A61BF4CE2481F4970017D9BC /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */; }; - A61BF4CF2481F4970017D9BC /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */; }; - A61BF4D02481F4970017D9BC /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */; }; - A61BF4D12481F4970017D9BC /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */; }; - A61BF4D22481F4970017D9BC /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */; }; - A61BF4D32481F4970017D9BC /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6241B98586A004E342D /* SwiftyStoreKit.swift */; }; - A61BF4D42481F4970017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61BF4BD2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift */; }; - A61BF4E02481F7400017D9BC /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = A61BF4DF2481F7150017D9BC /* SwiftyStoreKit-watchOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C3099C071E2FCDAA00392A54 /* PaymentsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3099C061E2FCDAA00392A54 /* PaymentsControllerTests.swift */; }; - C3099C091E2FCE3A00392A54 /* TestProduct.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3099C081E2FCE3A00392A54 /* TestProduct.swift */; }; - C3099C0B1E2FD13200392A54 /* TestPaymentTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3099C0A1E2FD13200392A54 /* TestPaymentTransaction.swift */; }; - C3099C191E3206C700392A54 /* CompleteTransactionsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3099C181E3206C700392A54 /* CompleteTransactionsControllerTests.swift */; }; - C4083C551C2AADB500295248 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */; }; - C4083C571C2AB0A900295248 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */; }; - C40C68101C29414C00B60B7E /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C680F1C29414C00B60B7E /* OS.swift */; }; - C40C68111C29419500B60B7E /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C680F1C29414C00B60B7E /* OS.swift */; }; - C4A7C7631C29B8D00053ED64 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */; }; - C4D74BC41C24CEDC0071AD3E /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6231B98586A004E342D /* InAppProductQueryRequest.swift */; }; - C4D74BC51C24CEDC0071AD3E /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6502F6241B98586A004E342D /* SwiftyStoreKit.swift */; }; - C4F69A8A1C2E0D21009DD8BD /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */; }; C4FD3A101C2954CD0035CFF3 /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */; }; C4FD3A111C2954CD0035CFF3 /* SwiftyStoreKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ @@ -181,33 +198,49 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleReceiptValidator.swift; sourceTree = ""; }; + 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "SKProductDiscount+LocalizedPrice.swift"; path = "Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift"; sourceTree = SOURCE_ROOT; }; + 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppleReceiptValidator.swift; path = Sources/SwiftyStoreKit/AppleReceiptValidator.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppProductQueryRequest.swift; path = Sources/SwiftyStoreKit/InAppProductQueryRequest.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceipt.swift; path = Sources/SwiftyStoreKit/InAppReceipt.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "SwiftyStoreKit+Types.swift"; path = "Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift"; sourceTree = SOURCE_ROOT; }; + 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CompleteTransactionsController.swift; path = Sources/SwiftyStoreKit/CompleteTransactionsController.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentQueueController.swift; path = Sources/SwiftyStoreKit/PaymentQueueController.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptRefreshRequest.swift; path = Sources/SwiftyStoreKit/InAppReceiptRefreshRequest.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptVerificator.swift; path = Sources/SwiftyStoreKit/InAppReceiptVerificator.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "SKProduct+LocalizedPrice.swift"; path = "Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift"; sourceTree = SOURCE_ROOT; }; + 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProductsInfoController.swift; path = Sources/SwiftyStoreKit/ProductsInfoController.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2C24A64CC100CEF088 /* OS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OS.swift; path = Sources/SwiftyStoreKit/OS.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentsController.swift; path = Sources/SwiftyStoreKit/PaymentsController.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyStoreKit.swift; path = Sources/SwiftyStoreKit/SwiftyStoreKit.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RestorePurchasesController.swift; path = Sources/SwiftyStoreKit/RestorePurchasesController.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SwiftyStoreKit-watchOS.h"; path = "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h"; sourceTree = SOURCE_ROOT; }; + 2F2B8B6D24A64CD700CEF088 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = "Info-macOS.plist"; path = "Sources/SwiftyStoreKit/Platforms/Info-macOS.plist"; sourceTree = SOURCE_ROOT; }; + 2F2B8B6E24A64CD700CEF088 /* Info-watchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = "Info-watchOS.plist"; path = "Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist"; sourceTree = SOURCE_ROOT; }; + 2F2B8B6F24A64CD700CEF088 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = "Info-iOS.plist"; path = "Sources/SwiftyStoreKit/Platforms/Info-iOS.plist"; sourceTree = SOURCE_ROOT; }; + 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SwiftyStoreKit-tvOS.h"; path = "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h"; sourceTree = SOURCE_ROOT; }; + 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SwiftyStoreKit-iOS.h"; path = "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h"; sourceTree = SOURCE_ROOT; }; + 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SwiftyStoreKit-macOS.h"; path = "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h"; sourceTree = SOURCE_ROOT; }; + 2F2B8B7324A64CD700CEF088 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = "Info-tvOS.plist"; path = "Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist"; sourceTree = SOURCE_ROOT; }; + 2F2B8B9424A64DE600CEF088 /* PaymentQueueControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentQueueControllerTests.swift; path = Tests/SwiftyStoreKitTests/PaymentQueueControllerTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9524A64DE600CEF088 /* PaymentTransactionObserverFake.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentTransactionObserverFake.swift; path = Tests/SwiftyStoreKitTests/PaymentTransactionObserverFake.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9624A64DE600CEF088 /* ProductsInfoControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProductsInfoControllerTests.swift; path = Tests/SwiftyStoreKitTests/ProductsInfoControllerTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9724A64DE600CEF088 /* TestPaymentTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestPaymentTransaction.swift; path = Tests/SwiftyStoreKitTests/TestPaymentTransaction.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9824A64DE600CEF088 /* TestProduct.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestProduct.swift; path = Tests/SwiftyStoreKitTests/TestProduct.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9924A64DE600CEF088 /* RestorePurchasesControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RestorePurchasesControllerTests.swift; path = Tests/SwiftyStoreKitTests/RestorePurchasesControllerTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9A24A64DE600CEF088 /* CompleteTransactionsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CompleteTransactionsControllerTests.swift; path = Tests/SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9B24A64DE600CEF088 /* InAppReceiptVerificatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptVerificatorTests.swift; path = Tests/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9C24A64DE600CEF088 /* InAppReceiptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptTests.swift; path = Tests/SwiftyStoreKitTests/InAppReceiptTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9D24A64DE600CEF088 /* PaymentsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentsControllerTests.swift; path = Tests/SwiftyStoreKitTests/PaymentsControllerTests.swift; sourceTree = SOURCE_ROOT; }; + 2F2B8B9E24A64DE600CEF088 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = Info.plist; path = Tests/SwiftyStoreKitTests/Info.plist; sourceTree = SOURCE_ROOT; }; + 2F2B8B9F24A64DE600CEF088 /* PaymentQueueSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentQueueSpy.swift; path = Tests/SwiftyStoreKitTests/PaymentQueueSpy.swift; sourceTree = SOURCE_ROOT; }; 54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6502F5FE1B985833004E342D /* SwiftyStoreKit_iOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyStoreKit_iOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 6502F6231B98586A004E342D /* InAppProductQueryRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppProductQueryRequest.swift; sourceTree = ""; }; - 6502F6241B98586A004E342D /* SwiftyStoreKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyStoreKit.swift; sourceTree = ""; }; 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 650307F11E3163AA001332A4 /* RestorePurchasesControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestorePurchasesControllerTests.swift; sourceTree = ""; }; - 650307F31E3177EF001332A4 /* RestorePurchasesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestorePurchasesController.swift; sourceTree = ""; }; - 650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompleteTransactionsController.swift; sourceTree = ""; }; - 650307FB1E33154F001332A4 /* ProductsInfoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductsInfoController.swift; sourceTree = ""; }; - 653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SKProduct+LocalizedPrice.swift"; sourceTree = ""; }; 654287EE1E79F5A000F61800 /* SwiftyStoreKit_tvOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyStoreKit_tvOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 654287F51E79F5A000F61800 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 654287F71E79F5A000F61800 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 654287F91E79F5A000F61800 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 658A08361E2EC24E0074A98F /* PaymentQueueController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentQueueController.swift; sourceTree = ""; }; 658A083E1E2EC5120074A98F /* SwiftyStoreKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftyStoreKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 658A08421E2EC5120074A98F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 658A08491E2EC5350074A98F /* PaymentQueueControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentQueueControllerTests.swift; sourceTree = ""; }; - 658A084B1E2EC5960074A98F /* PaymentQueueSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentQueueSpy.swift; sourceTree = ""; }; - 65B8C9281EC0BE62009439D9 /* InAppReceiptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptTests.swift; sourceTree = ""; }; - 65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftyStoreKit+Types.swift"; sourceTree = ""; }; - 65BF8E2F1F4AEEBA00CBFC00 /* ProductsInfoControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsInfoControllerTests.swift; sourceTree = ""; }; - 65CEF0F31ECC80D9007DC3B6 /* InAppReceiptVerificatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptVerificatorTests.swift; sourceTree = ""; }; - 65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptVerificator.swift; sourceTree = ""; }; - 65F70AC61E2ECBB300BF040D /* PaymentTransactionObserverFake.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentTransactionObserverFake.swift; sourceTree = ""; }; - 65F70AC81E2EDC3700BF040D /* PaymentsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentsController.swift; sourceTree = ""; }; 65F7DF681DCD4DF000835D30 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 65F7DF691DCD4DF000835D30 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 65F7DF6B1DCD4DF000835D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -220,23 +253,7 @@ 65F7DF811DCD4FC500835D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 65F7DF821DCD4FC500835D30 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65F7DF831DCD4FC500835D30 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 65F7DF941DCD536100835D30 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; - 65F7DF951DCD536100835D30 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; - 65F7DF961DCD536100835D30 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; - 65F7DF971DCD536100835D30 /* SwiftyStoreKit-iOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftyStoreKit-iOS.h"; sourceTree = ""; }; - 65F7DF981DCD536100835D30 /* SwiftyStoreKit-macOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftyStoreKit-macOS.h"; sourceTree = ""; }; - 65F7DF991DCD536100835D30 /* SwiftyStoreKit-tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftyStoreKit-tvOS.h"; sourceTree = ""; }; - A61BF4BD2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SKProductDiscount+LocalizedPrice.swift"; sourceTree = ""; }; A61BF4DD2481F4970017D9BC /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - A61BF4DF2481F7150017D9BC /* SwiftyStoreKit-watchOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftyStoreKit-watchOS.h"; sourceTree = ""; }; - A61BF4E12481F7B00017D9BC /* Info-watchOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-watchOS.plist"; sourceTree = ""; }; - C3099C061E2FCDAA00392A54 /* PaymentsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentsControllerTests.swift; sourceTree = ""; }; - C3099C081E2FCE3A00392A54 /* TestProduct.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestProduct.swift; sourceTree = ""; }; - C3099C0A1E2FD13200392A54 /* TestPaymentTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestPaymentTransaction.swift; sourceTree = ""; }; - C3099C181E3206C700392A54 /* CompleteTransactionsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompleteTransactionsControllerTests.swift; sourceTree = ""; }; - C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptRefreshRequest.swift; sourceTree = ""; }; - C40C680F1C29414C00B60B7E /* OS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OS.swift; sourceTree = ""; }; - C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceipt.swift; sourceTree = ""; }; C4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C4FD3A011C2954C10035CFF3 /* SwiftyStoreKit_macOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyStoreKit_macOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -335,21 +352,21 @@ 6502F6001B985833004E342D /* SwiftyStoreKit */ = { isa = PBXGroup; children = ( - 6502F6241B98586A004E342D /* SwiftyStoreKit.swift */, - 65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */, - 650307FB1E33154F001332A4 /* ProductsInfoController.swift */, - 6502F6231B98586A004E342D /* InAppProductQueryRequest.swift */, - 658A08361E2EC24E0074A98F /* PaymentQueueController.swift */, - 65F70AC81E2EDC3700BF040D /* PaymentsController.swift */, - 650307F31E3177EF001332A4 /* RestorePurchasesController.swift */, - 650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */, - C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */, - C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */, - 65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */, - 1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */, - 653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */, - A61BF4BD2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift */, - C40C680F1C29414C00B60B7E /* OS.swift */, + 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */, + 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */, + 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */, + 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */, + 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */, + 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */, + 2F2B8B2C24A64CC100CEF088 /* OS.swift */, + 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */, + 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */, + 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */, + 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */, + 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */, + 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */, + 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */, + 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */, 65F7DF931DCD536100835D30 /* Platforms */, ); path = SwiftyStoreKit; @@ -368,18 +385,18 @@ 658A083F1E2EC5120074A98F /* SwiftyStoreKitTests */ = { isa = PBXGroup; children = ( - 658A08421E2EC5120074A98F /* Info.plist */, - 658A08491E2EC5350074A98F /* PaymentQueueControllerTests.swift */, - C3099C061E2FCDAA00392A54 /* PaymentsControllerTests.swift */, - 650307F11E3163AA001332A4 /* RestorePurchasesControllerTests.swift */, - C3099C181E3206C700392A54 /* CompleteTransactionsControllerTests.swift */, - 65B8C9281EC0BE62009439D9 /* InAppReceiptTests.swift */, - 65CEF0F31ECC80D9007DC3B6 /* InAppReceiptVerificatorTests.swift */, - 658A084B1E2EC5960074A98F /* PaymentQueueSpy.swift */, - 65F70AC61E2ECBB300BF040D /* PaymentTransactionObserverFake.swift */, - C3099C081E2FCE3A00392A54 /* TestProduct.swift */, - C3099C0A1E2FD13200392A54 /* TestPaymentTransaction.swift */, - 65BF8E2F1F4AEEBA00CBFC00 /* ProductsInfoControllerTests.swift */, + 2F2B8B9A24A64DE600CEF088 /* CompleteTransactionsControllerTests.swift */, + 2F2B8B9C24A64DE600CEF088 /* InAppReceiptTests.swift */, + 2F2B8B9B24A64DE600CEF088 /* InAppReceiptVerificatorTests.swift */, + 2F2B8B9E24A64DE600CEF088 /* Info.plist */, + 2F2B8B9424A64DE600CEF088 /* PaymentQueueControllerTests.swift */, + 2F2B8B9F24A64DE600CEF088 /* PaymentQueueSpy.swift */, + 2F2B8B9D24A64DE600CEF088 /* PaymentsControllerTests.swift */, + 2F2B8B9524A64DE600CEF088 /* PaymentTransactionObserverFake.swift */, + 2F2B8B9624A64DE600CEF088 /* ProductsInfoControllerTests.swift */, + 2F2B8B9924A64DE600CEF088 /* RestorePurchasesControllerTests.swift */, + 2F2B8B9724A64DE600CEF088 /* TestPaymentTransaction.swift */, + 2F2B8B9824A64DE600CEF088 /* TestProduct.swift */, ); path = SwiftyStoreKitTests; sourceTree = ""; @@ -413,14 +430,14 @@ 65F7DF931DCD536100835D30 /* Platforms */ = { isa = PBXGroup; children = ( - 65F7DF941DCD536100835D30 /* Info-iOS.plist */, - 65F7DF951DCD536100835D30 /* Info-macOS.plist */, - 65F7DF961DCD536100835D30 /* Info-tvOS.plist */, - A61BF4E12481F7B00017D9BC /* Info-watchOS.plist */, - 65F7DF971DCD536100835D30 /* SwiftyStoreKit-iOS.h */, - 65F7DF981DCD536100835D30 /* SwiftyStoreKit-macOS.h */, - 65F7DF991DCD536100835D30 /* SwiftyStoreKit-tvOS.h */, - A61BF4DF2481F7150017D9BC /* SwiftyStoreKit-watchOS.h */, + 2F2B8B6F24A64CD700CEF088 /* Info-iOS.plist */, + 2F2B8B6D24A64CD700CEF088 /* Info-macOS.plist */, + 2F2B8B7324A64CD700CEF088 /* Info-tvOS.plist */, + 2F2B8B6E24A64CD700CEF088 /* Info-watchOS.plist */, + 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */, + 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */, + 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */, + 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */, ); path = Platforms; sourceTree = ""; @@ -432,7 +449,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 65F7DF9C1DCD537F00835D30 /* SwiftyStoreKit-tvOS.h in Headers */, + 2F2B8B8A24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */, + 2F2B8B7624A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */, + 2F2B8B8624A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */, + 2F2B8B8E24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -440,7 +460,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 65F7DF9A1DCD536700835D30 /* SwiftyStoreKit-iOS.h in Headers */, + 2F2B8B8824A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */, + 2F2B8B7424A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */, + 2F2B8B8424A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */, + 2F2B8B8C24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -448,7 +471,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - A61BF4E02481F7400017D9BC /* SwiftyStoreKit-watchOS.h in Headers */, + 2F2B8B8B24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */, + 2F2B8B7724A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */, + 2F2B8B8724A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */, + 2F2B8B8F24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -456,7 +482,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 65F7DF9B1DCD537800835D30 /* SwiftyStoreKit-macOS.h in Headers */, + 2F2B8B8924A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */, + 2F2B8B7524A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */, + 2F2B8B8524A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */, + 2F2B8B8D24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -627,6 +656,7 @@ 54C0D52B1CF7404500F90BCE = { CreatedOnToolsVersion = 7.3.1; DevelopmentTeam = M54ZVB688G; + LastSwiftMigration = 1150; }; 6502F5FD1B985833004E342D = { CreatedOnToolsVersion = 7.0; @@ -635,7 +665,7 @@ }; 6502F62C1B985C40004E342D = { CreatedOnToolsVersion = 7.0; - LastSwiftMigration = 1020; + LastSwiftMigration = 1150; }; 654287ED1E79F5A000F61800 = { CreatedOnToolsVersion = 8.2.1; @@ -647,8 +677,12 @@ ProvisioningStyle = Automatic; TestTargetID = 6502F5FD1B985833004E342D; }; + A61BF4C42481F4970017D9BC = { + LastSwiftMigration = 1150; + }; C4D74BBA1C24CEC90071AD3E = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1150; }; C4FD3A001C2954C10035CFF3 = { CreatedOnToolsVersion = 7.2; @@ -686,6 +720,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2F2B8B9224A64CD700CEF088 /* Info-tvOS.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -703,6 +738,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2F2B8B8024A64CD700CEF088 /* Info-iOS.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -719,6 +755,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2F2B8BAA24A64DE600CEF088 /* Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -726,6 +763,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2F2B8B7F24A64CD700CEF088 /* Info-watchOS.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -733,6 +771,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2F2B8B7924A64CD700CEF088 /* Info-macOS.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -797,21 +836,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1592CD521E27756500D321E6 /* AppleReceiptValidator.swift in Sources */, - 54C0D5681CF7428400F90BCE /* SwiftyStoreKit.swift in Sources */, - 54B069961CF744DC00BAFE38 /* OS.swift in Sources */, - 54B069931CF742D300BAFE38 /* InAppReceiptRefreshRequest.swift in Sources */, - 65F70ACB1E2EDC3700BF040D /* PaymentsController.swift in Sources */, - 650307FE1E33154F001332A4 /* ProductsInfoController.swift in Sources */, - 650307F61E3177EF001332A4 /* RestorePurchasesController.swift in Sources */, - 658A08391E2EC24E0074A98F /* PaymentQueueController.swift in Sources */, - 65E9E07B1ECADF5E005CF7B4 /* InAppReceiptVerificator.swift in Sources */, - 653722831DB8290B00C8F944 /* SKProduct+LocalizedPrice.swift in Sources */, - 54B069921CF742D100BAFE38 /* InAppReceipt.swift in Sources */, - 650307FA1E317BCF001332A4 /* CompleteTransactionsController.swift in Sources */, - 65BB6CEA1DDB018900218A0B /* SwiftyStoreKit+Types.swift in Sources */, - 54B069941CF742D600BAFE38 /* InAppProductQueryRequest.swift in Sources */, - A61BF4C02481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B3A24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */, + 2F2B8B6224A64CC100CEF088 /* PaymentsController.swift in Sources */, + 2F2B8B5624A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */, + 2F2B8B3E24A64CC100CEF088 /* InAppReceipt.swift in Sources */, + 2F2B8B3624A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */, + 2F2B8B6A24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */, + 2F2B8B4624A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */, + 2F2B8B5E24A64CC100CEF088 /* OS.swift in Sources */, + 2F2B8B5224A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */, + 2F2B8B6624A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */, + 2F2B8B4A24A64CC100CEF088 /* PaymentQueueController.swift in Sources */, + 2F2B8B4224A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */, + 2F2B8B4E24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */, + 2F2B8B3224A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B5A24A64CC100CEF088 /* ProductsInfoController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -829,21 +868,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C40C68101C29414C00B60B7E /* OS.swift in Sources */, - 1592CD501E27756500D321E6 /* AppleReceiptValidator.swift in Sources */, - 6502F63B1B985CA1004E342D /* InAppProductQueryRequest.swift in Sources */, - C4083C571C2AB0A900295248 /* InAppReceiptRefreshRequest.swift in Sources */, - 65F70AC91E2EDC3700BF040D /* PaymentsController.swift in Sources */, - 650307FC1E33154F001332A4 /* ProductsInfoController.swift in Sources */, - 650307F41E3177EF001332A4 /* RestorePurchasesController.swift in Sources */, - 658A08371E2EC24E0074A98F /* PaymentQueueController.swift in Sources */, - 65E9E0791ECADF5E005CF7B4 /* InAppReceiptVerificator.swift in Sources */, - 653722811DB8282600C8F944 /* SKProduct+LocalizedPrice.swift in Sources */, - C4A7C7631C29B8D00053ED64 /* InAppReceipt.swift in Sources */, - 650307F81E317BCF001332A4 /* CompleteTransactionsController.swift in Sources */, - 65BB6CE81DDB018900218A0B /* SwiftyStoreKit+Types.swift in Sources */, - 6502F63C1B985CA4004E342D /* SwiftyStoreKit.swift in Sources */, - A61BF4BE2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B3824A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */, + 2F2B8B6024A64CC100CEF088 /* PaymentsController.swift in Sources */, + 2F2B8B5424A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */, + 2F2B8B3C24A64CC100CEF088 /* InAppReceipt.swift in Sources */, + 2F2B8B3424A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */, + 2F2B8B6824A64CC100CEF088 /* RestorePurchasesController.swift in Sources */, + 2F2B8B4424A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */, + 2F2B8B5C24A64CC100CEF088 /* OS.swift in Sources */, + 2F2B8B5024A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */, + 2F2B8B6424A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */, + 2F2B8B4824A64CC100CEF088 /* PaymentQueueController.swift in Sources */, + 2F2B8B4024A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */, + 2F2B8B4C24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */, + 2F2B8B3024A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B5824A64CC100CEF088 /* ProductsInfoController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -861,17 +900,17 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C3099C071E2FCDAA00392A54 /* PaymentsControllerTests.swift in Sources */, - 650307F21E3163AA001332A4 /* RestorePurchasesControllerTests.swift in Sources */, - 65BF8E301F4AEEBA00CBFC00 /* ProductsInfoControllerTests.swift in Sources */, - 65CEF0F41ECC80D9007DC3B6 /* InAppReceiptVerificatorTests.swift in Sources */, - C3099C0B1E2FD13200392A54 /* TestPaymentTransaction.swift in Sources */, - 65F70AC71E2ECBB300BF040D /* PaymentTransactionObserverFake.swift in Sources */, - 658A084A1E2EC5350074A98F /* PaymentQueueControllerTests.swift in Sources */, - C3099C191E3206C700392A54 /* CompleteTransactionsControllerTests.swift in Sources */, - 658A084C1E2EC5960074A98F /* PaymentQueueSpy.swift in Sources */, - C3099C091E2FCE3A00392A54 /* TestProduct.swift in Sources */, - 65B8C9291EC0BE62009439D9 /* InAppReceiptTests.swift in Sources */, + 2F2B8BA924A64DE600CEF088 /* PaymentsControllerTests.swift in Sources */, + 2F2B8BA224A64DE600CEF088 /* ProductsInfoControllerTests.swift in Sources */, + 2F2B8BA524A64DE600CEF088 /* RestorePurchasesControllerTests.swift in Sources */, + 2F2B8BA724A64DE600CEF088 /* InAppReceiptVerificatorTests.swift in Sources */, + 2F2B8BA124A64DE600CEF088 /* PaymentTransactionObserverFake.swift in Sources */, + 2F2B8BAB24A64DE600CEF088 /* PaymentQueueSpy.swift in Sources */, + 2F2B8BA624A64DE600CEF088 /* CompleteTransactionsControllerTests.swift in Sources */, + 2F2B8BA024A64DE600CEF088 /* PaymentQueueControllerTests.swift in Sources */, + 2F2B8BA324A64DE600CEF088 /* TestPaymentTransaction.swift in Sources */, + 2F2B8BA424A64DE600CEF088 /* TestProduct.swift in Sources */, + 2F2B8BA824A64DE600CEF088 /* InAppReceiptTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -879,21 +918,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A61BF4C62481F4970017D9BC /* OS.swift in Sources */, - A61BF4C72481F4970017D9BC /* AppleReceiptValidator.swift in Sources */, - A61BF4C82481F4970017D9BC /* InAppProductQueryRequest.swift in Sources */, - A61BF4C92481F4970017D9BC /* InAppReceiptRefreshRequest.swift in Sources */, - A61BF4CA2481F4970017D9BC /* PaymentsController.swift in Sources */, - A61BF4CB2481F4970017D9BC /* ProductsInfoController.swift in Sources */, - A61BF4CC2481F4970017D9BC /* RestorePurchasesController.swift in Sources */, - A61BF4CD2481F4970017D9BC /* PaymentQueueController.swift in Sources */, - A61BF4CE2481F4970017D9BC /* InAppReceiptVerificator.swift in Sources */, - A61BF4CF2481F4970017D9BC /* SKProduct+LocalizedPrice.swift in Sources */, - A61BF4D02481F4970017D9BC /* InAppReceipt.swift in Sources */, - A61BF4D12481F4970017D9BC /* CompleteTransactionsController.swift in Sources */, - A61BF4D22481F4970017D9BC /* SwiftyStoreKit+Types.swift in Sources */, - A61BF4D32481F4970017D9BC /* SwiftyStoreKit.swift in Sources */, - A61BF4D42481F4970017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B3B24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */, + 2F2B8B6324A64CC100CEF088 /* PaymentsController.swift in Sources */, + 2F2B8B5724A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */, + 2F2B8B3F24A64CC100CEF088 /* InAppReceipt.swift in Sources */, + 2F2B8B3724A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */, + 2F2B8B6B24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */, + 2F2B8B4724A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */, + 2F2B8B5F24A64CC100CEF088 /* OS.swift in Sources */, + 2F2B8B5324A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */, + 2F2B8B6724A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */, + 2F2B8B4B24A64CC100CEF088 /* PaymentQueueController.swift in Sources */, + 2F2B8B4324A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */, + 2F2B8B4F24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */, + 2F2B8B3324A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B5B24A64CC100CEF088 /* ProductsInfoController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -901,21 +940,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C40C68111C29419500B60B7E /* OS.swift in Sources */, - 1592CD511E27756500D321E6 /* AppleReceiptValidator.swift in Sources */, - C4D74BC41C24CEDC0071AD3E /* InAppProductQueryRequest.swift in Sources */, - C4F69A8A1C2E0D21009DD8BD /* InAppReceiptRefreshRequest.swift in Sources */, - 65F70ACA1E2EDC3700BF040D /* PaymentsController.swift in Sources */, - 650307FD1E33154F001332A4 /* ProductsInfoController.swift in Sources */, - 650307F51E3177EF001332A4 /* RestorePurchasesController.swift in Sources */, - 658A08381E2EC24E0074A98F /* PaymentQueueController.swift in Sources */, - 65E9E07A1ECADF5E005CF7B4 /* InAppReceiptVerificator.swift in Sources */, - 653722821DB8290A00C8F944 /* SKProduct+LocalizedPrice.swift in Sources */, - C4083C551C2AADB500295248 /* InAppReceipt.swift in Sources */, - 650307F91E317BCF001332A4 /* CompleteTransactionsController.swift in Sources */, - 65BB6CE91DDB018900218A0B /* SwiftyStoreKit+Types.swift in Sources */, - C4D74BC51C24CEDC0071AD3E /* SwiftyStoreKit.swift in Sources */, - A61BF4BF2481F0560017D9BC /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B3924A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */, + 2F2B8B6124A64CC100CEF088 /* PaymentsController.swift in Sources */, + 2F2B8B5524A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */, + 2F2B8B3D24A64CC100CEF088 /* InAppReceipt.swift in Sources */, + 2F2B8B3524A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */, + 2F2B8B6924A64CC100CEF088 /* RestorePurchasesController.swift in Sources */, + 2F2B8B4524A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */, + 2F2B8B5D24A64CC100CEF088 /* OS.swift in Sources */, + 2F2B8B5124A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */, + 2F2B8B6524A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */, + 2F2B8B4924A64CC100CEF088 /* PaymentQueueController.swift in Sources */, + 2F2B8B4124A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */, + 2F2B8B4D24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */, + 2F2B8B3124A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */, + 2F2B8B5924A64CC100CEF088 /* ProductsInfoController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -998,6 +1037,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; @@ -1005,13 +1045,15 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-tvOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.musevisions.tvOS.SwiftyStoreKit; PRODUCT_NAME = SwiftyStoreKit; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; @@ -1023,6 +1065,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; @@ -1030,7 +1073,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-tvOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.musevisions.tvOS.SwiftyStoreKit; @@ -1038,6 +1081,7 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; @@ -1189,6 +1233,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; @@ -1196,13 +1241,14 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-iOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-iOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKit; PRODUCT_NAME = SwiftyStoreKit; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -1214,6 +1260,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; @@ -1221,7 +1268,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-iOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-iOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1283,7 +1330,9 @@ 658A08471E2EC5120074A98F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; INFOPLIST_FILE = SwiftyStoreKitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.2; @@ -1291,6 +1340,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftyStoreKit_iOSDemo.app/SwiftyStoreKit_iOSDemo"; @@ -1300,7 +1350,9 @@ 658A08481E2EC5120074A98F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; INFOPLIST_FILE = SwiftyStoreKitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.2; @@ -1318,6 +1370,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; @@ -1325,7 +1378,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-watchOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1334,6 +1387,7 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; VERSIONING_SYSTEM = "apple-generic"; @@ -1345,6 +1399,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; @@ -1352,7 +1407,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-watchOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1372,6 +1427,7 @@ C4D74BC01C24CECA0071AD3E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -1380,7 +1436,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-macOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-macOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; @@ -1388,6 +1444,8 @@ PRODUCT_NAME = SwiftyStoreKit; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1396,6 +1454,7 @@ C4D74BC11C24CECA0071AD3E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -1404,7 +1463,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit/Platforms/Info-macOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-macOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; @@ -1413,6 +1472,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit_watchOS.xcscheme b/SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit_watchOS.xcscheme index 1b980df5..8ccad740 100644 --- a/SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit_watchOS.xcscheme +++ b/SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit_watchOS.xcscheme @@ -15,7 +15,7 @@ @@ -51,7 +51,7 @@ diff --git a/SwiftyStoreKit/AppleReceiptValidator.swift b/SwiftyStoreKit/AppleReceiptValidator.swift deleted file mode 100644 index b0432e21..00000000 --- a/SwiftyStoreKit/AppleReceiptValidator.swift +++ /dev/null @@ -1,127 +0,0 @@ -// -// InAppReceipt.swift -// SwiftyStoreKit -// -// Created by phimage on 22/12/15. -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -// https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html - -public class AppleReceiptValidator: ReceiptValidator { - - public enum VerifyReceiptURLType: String { - case production = "https://buy.itunes.apple.com/verifyReceipt" - case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt" - } - - /// You should always verify your receipt first with the `production` service - /// Note: will auto change to `.sandbox` and validate again if received a 21007 status code from Apple - public var service: VerifyReceiptURLType - - private let sharedSecret: String? - - /** - * Reference Apple Receipt Validator - * - Parameter service: Either .production or .sandbox - * - Parameter sharedSecret: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string). - */ - public init(service: VerifyReceiptURLType = .production, sharedSecret: String? = nil) { - self.service = service - self.sharedSecret = sharedSecret - } - - public func validate(receiptData: Data, completion: @escaping (VerifyReceiptResult) -> Void) { - - let storeURL = URL(string: service.rawValue)! // safe (until no more) - let storeRequest = NSMutableURLRequest(url: storeURL) - storeRequest.httpMethod = "POST" - - let receipt = receiptData.base64EncodedString(options: []) - let requestContents: NSMutableDictionary = [ "receipt-data": receipt ] - // password if defined - if let password = sharedSecret { - requestContents.setValue(password, forKey: "password") - } - - // Encore request body - do { - storeRequest.httpBody = try JSONSerialization.data(withJSONObject: requestContents, options: []) - } catch let e { - completion(.error(error: .requestBodyEncodeError(error: e))) - return - } - - // Remote task - let task = URLSession.shared.dataTask(with: storeRequest as URLRequest) { data, _, error -> Void in - - // there is an error - if let networkError = error { - completion(.error(error: .networkError(error: networkError))) - return - } - - // there is no data - guard let safeData = data else { - completion(.error(error: .noRemoteData)) - return - } - - // cannot decode data - guard let receiptInfo = try? JSONSerialization.jsonObject(with: safeData, options: .mutableLeaves) as? ReceiptInfo ?? [:] else { - let jsonStr = String(data: safeData, encoding: String.Encoding.utf8) - completion(.error(error: .jsonDecodeError(string: jsonStr))) - return - } - - // get status from info - if let status = receiptInfo["status"] as? Int { - /* - * http://stackoverflow.com/questions/16187231/how-do-i-know-if-an-in-app-purchase-receipt-comes-from-the-sandbox - * How do I verify my receipt (iOS)? - * Always verify your receipt first with the production URL; proceed to verify - * with the sandbox URL if you receive a 21007 status code. Following this - * approach ensures that you do not have to switch between URLs while your - * application is being tested or reviewed in the sandbox or is live in the - * App Store. - - * Note: The 21007 status code indicates that this receipt is a sandbox receipt, - * but it was sent to the production service for verification. - */ - let receiptStatus = ReceiptStatus(rawValue: status) ?? ReceiptStatus.unknown - if case .testReceipt = receiptStatus { - self.service = .sandbox - self.validate(receiptData: receiptData, completion: completion) - } else { - if receiptStatus.isValid { - completion(.success(receipt: receiptInfo)) - } else { - completion(.error(error: .receiptInvalid(receipt: receiptInfo, status: receiptStatus))) - } - } - } else { - completion(.error(error: .receiptInvalid(receipt: receiptInfo, status: ReceiptStatus.none))) - } - } - task.resume() - } -} diff --git a/SwiftyStoreKit/CompleteTransactionsController.swift b/SwiftyStoreKit/CompleteTransactionsController.swift deleted file mode 100644 index 0ee898ac..00000000 --- a/SwiftyStoreKit/CompleteTransactionsController.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// CompleteTransactionsController.swift -// SwiftyStoreKit -// -// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation -import StoreKit - -struct CompleteTransactions { - let atomically: Bool - let callback: ([Purchase]) -> Void - - init(atomically: Bool, callback: @escaping ([Purchase]) -> Void) { - self.atomically = atomically - self.callback = callback - } -} - -class CompleteTransactionsController: TransactionController { - - var completeTransactions: CompleteTransactions? - - func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] { - - guard let completeTransactions = completeTransactions else { - print("SwiftyStoreKit.completeTransactions() should be called once when the app launches.") - return transactions - } - - var unhandledTransactions: [SKPaymentTransaction] = [] - var purchases: [Purchase] = [] - - for transaction in transactions { - - let transactionState = transaction.transactionState - - if transactionState != .purchasing { - - let willFinishTransaction = completeTransactions.atomically || transactionState == .failed - let purchase = Purchase(productId: transaction.payment.productIdentifier, quantity: transaction.payment.quantity, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !willFinishTransaction) - - purchases.append(purchase) - - if willFinishTransaction { - print("Finishing transaction for payment \"\(transaction.payment.productIdentifier)\" with state: \(transactionState.debugDescription)") - paymentQueue.finishTransaction(transaction) - } - } else { - unhandledTransactions.append(transaction) - } - } - if purchases.count > 0 { - completeTransactions.callback(purchases) - } - - return unhandledTransactions - } -} diff --git a/SwiftyStoreKit/InAppProductQueryRequest.swift b/SwiftyStoreKit/InAppProductQueryRequest.swift deleted file mode 100644 index 97c9f889..00000000 --- a/SwiftyStoreKit/InAppProductQueryRequest.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// InAppPurchaseProductRequest.swift -// SwiftyStoreKit -// -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit - -typealias InAppProductRequestCallback = (RetrieveResults) -> Void - -public protocol InAppRequest: class { - func start() - func cancel() -} - -protocol InAppProductRequest: InAppRequest { } - -class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequestDelegate { - - private let callback: InAppProductRequestCallback - private let request: SKProductsRequest - - deinit { - request.delegate = nil - } - init(productIds: Set, callback: @escaping InAppProductRequestCallback) { - - self.callback = callback - request = SKProductsRequest(productIdentifiers: productIds) - super.init() - request.delegate = self - } - - func start() { - request.start() - } - func cancel() { - request.cancel() - } - - // MARK: SKProductsRequestDelegate - func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { - - let retrievedProducts = Set(response.products) - let invalidProductIDs = Set(response.invalidProductIdentifiers) - performCallback(RetrieveResults(retrievedProducts: retrievedProducts, - invalidProductIDs: invalidProductIDs, error: nil)) - } - - func requestDidFinish(_ request: SKRequest) { - - } - - func request(_ request: SKRequest, didFailWithError error: Error) { - performCallback(RetrieveResults(retrievedProducts: Set(), invalidProductIDs: Set(), error: error)) - } - - private func performCallback(_ results: RetrieveResults) { - DispatchQueue.main.async { - self.callback(results) - } - } -} diff --git a/SwiftyStoreKit/InAppReceipt.swift b/SwiftyStoreKit/InAppReceipt.swift deleted file mode 100644 index a31b23a2..00000000 --- a/SwiftyStoreKit/InAppReceipt.swift +++ /dev/null @@ -1,285 +0,0 @@ -// -// InAppReceipt.swift -// SwiftyStoreKit -// -// Created by phimage on 22/12/15. -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -extension Date { - - init?(millisecondsSince1970: String) { - guard let millisecondsNumber = Double(millisecondsSince1970) else { - return nil - } - self = Date(timeIntervalSince1970: millisecondsNumber / 1000) - } -} - -extension ReceiptItem { - - public init?(receiptInfo: ReceiptInfo) { - guard - let productId = receiptInfo["product_id"] as? String, - let quantityString = receiptInfo["quantity"] as? String, - let quantity = Int(quantityString), - let transactionId = receiptInfo["transaction_id"] as? String, - let originalTransactionId = receiptInfo["original_transaction_id"] as? String, - let purchaseDate = ReceiptItem.parseDate(from: receiptInfo, key: "purchase_date_ms"), - let originalPurchaseDate = ReceiptItem.parseDate(from: receiptInfo, key: "original_purchase_date_ms") - else { - print("could not parse receipt item: \(receiptInfo). Skipping...") - return nil - } - self.productId = productId - self.quantity = quantity - self.transactionId = transactionId - self.originalTransactionId = originalTransactionId - self.purchaseDate = purchaseDate - self.originalPurchaseDate = originalPurchaseDate - self.webOrderLineItemId = receiptInfo["web_order_line_item_id"] as? String - self.subscriptionExpirationDate = ReceiptItem.parseDate(from: receiptInfo, key: "expires_date_ms") - self.cancellationDate = ReceiptItem.parseDate(from: receiptInfo, key: "cancellation_date_ms") - if let isTrialPeriod = receiptInfo["is_trial_period"] as? String { - self.isTrialPeriod = Bool(isTrialPeriod) ?? false - } else { - self.isTrialPeriod = false - } - if let isInIntroOfferPeriod = receiptInfo["is_in_intro_offer_period"] as? String { - self.isInIntroOfferPeriod = Bool(isInIntroOfferPeriod) ?? false - } else { - self.isInIntroOfferPeriod = false - } - } - - private static func parseDate(from receiptInfo: ReceiptInfo, key: String) -> Date? { - - guard - let requestDateString = receiptInfo[key] as? String, - let requestDateMs = Double(requestDateString) else { - return nil - } - return Date(timeIntervalSince1970: requestDateMs / 1000) - } -} - -// MARK: - receipt mangement -internal class InAppReceipt { - - /** - * Verify the purchase of a Consumable or NonConsumable product in a receipt - * - Parameter productId: the product id of the purchase to verify - * - Parameter inReceipt: the receipt to use for looking up the purchase - * - return: either notPurchased or purchased - */ - class func verifyPurchase( - productId: String, - inReceipt receipt: ReceiptInfo - ) -> VerifyPurchaseResult { - - // Get receipts info for the product - let receipts = getInAppReceipts(receipt: receipt) - let filteredReceiptsInfo = filterReceiptsInfo(receipts: receipts, withProductIds: [productId]) - let nonCancelledReceiptsInfo = filteredReceiptsInfo.filter { receipt in receipt["cancellation_date"] == nil } - - #if swift(>=4.1) - let receiptItems = nonCancelledReceiptsInfo.compactMap { ReceiptItem(receiptInfo: $0) } - #else - let receiptItems = nonCancelledReceiptsInfo.flatMap { ReceiptItem(receiptInfo: $0) } - #endif - - // Verify that at least one receipt has the right product id - if let firstItem = receiptItems.first { - return .purchased(item: firstItem) - } - return .notPurchased - } - - /** - * Verify the validity of a set of subscriptions in a receipt. - * - * This method extracts all transactions matching the given productIds and sorts them by date in descending order. It then compares the first transaction expiry date against the receipt date, to determine its validity. - * - Note: You can use this method to check the validity of (mutually exclusive) subscriptions in a subscription group. - * - Remark: The type parameter determines how the expiration dates are calculated for all subscriptions. Make sure all productIds match the specified subscription type to avoid incorrect results. - * - Parameter type: .autoRenewable or .nonRenewing. - * - Parameter productIds: The product ids of the subscriptions to verify. - * - Parameter receipt: The receipt to use for looking up the subscriptions - * - Parameter validUntil: Date to check against the expiry date of the subscriptions. This is only used if a date is not found in the receipt. - * - return: Either .notPurchased or .purchased / .expired with the expiry date found in the receipt. - */ - class func verifySubscriptions( - ofType type: SubscriptionType, - productIds: Set, - inReceipt receipt: ReceiptInfo, - validUntil date: Date = Date() - ) -> VerifySubscriptionResult { - - // The values of the latest_receipt and latest_receipt_info keys are useful when checking whether an auto-renewable subscription is currently active. By providing any transaction receipt for the subscription and checking these values, you can get information about the currently-active subscription period. If the receipt being validated is for the latest renewal, the value for latest_receipt is the same as receipt-data (in the request) and the value for latest_receipt_info is the same as receipt. - let (receipts, duration) = getReceiptsAndDuration(for: type, inReceipt: receipt) - let receiptsInfo = filterReceiptsInfo(receipts: receipts, withProductIds: productIds) - let nonCancelledReceiptsInfo = receiptsInfo.filter { receipt in receipt["cancellation_date"] == nil } - if nonCancelledReceiptsInfo.count == 0 { - return .notPurchased - } - - let receiptDate = getReceiptRequestDate(inReceipt: receipt) ?? date - - #if swift(>=4.1) - let receiptItems = nonCancelledReceiptsInfo.compactMap { ReceiptItem(receiptInfo: $0) } - #else - let receiptItems = nonCancelledReceiptsInfo.flatMap { ReceiptItem(receiptInfo: $0) } - #endif - - if nonCancelledReceiptsInfo.count > receiptItems.count { - print("receipt has \(nonCancelledReceiptsInfo.count) items, but only \(receiptItems.count) were parsed") - } - - let sortedExpiryDatesAndItems = expiryDatesAndItems(receiptItems: receiptItems, duration: duration).sorted { a, b in - return a.0 > b.0 - } - - guard let firstExpiryDateItemPair = sortedExpiryDatesAndItems.first else { - return .notPurchased - } - - let sortedReceiptItems = sortedExpiryDatesAndItems.map { $0.1 } - if firstExpiryDateItemPair.0 > receiptDate { - return .purchased(expiryDate: firstExpiryDateItemPair.0, items: sortedReceiptItems) - } else { - return .expired(expiryDate: firstExpiryDateItemPair.0, items: sortedReceiptItems) - } - } - - /** - * Get the distinct product identifiers from receipt. - * - * This Method extracts all product identifiers. (Including cancelled ones). - * - Note: You can use this method to get all unique product identifiers from receipt. - * - Parameter type: .autoRenewable or .nonRenewing. - * - Parameter receipt: The receipt to use for looking up the product identifiers. - * - return: Either Set or nil. - */ - class func getDistinctPurchaseIds( - ofType type: SubscriptionType, - inReceipt receipt: ReceiptInfo - ) -> Set? { - - // Get receipts array from receipt - guard let receipts = getReceipts(for: type, inReceipt: receipt) else { - return nil - } - - #if swift(>=4.1) - let receiptIds = receipts.compactMap { ReceiptItem(receiptInfo: $0)?.productId } - #else - let receiptIds = receipts.flatMap { ReceiptItem(receiptInfo: $0)?.productId } - #endif - - if receiptIds.isEmpty { - return nil - } - - return Set(receiptIds) - } - - private class func expiryDatesAndItems(receiptItems: [ReceiptItem], duration: TimeInterval?) -> [(Date, ReceiptItem)] { - - if let duration = duration { - return receiptItems.map { - let expirationDate = Date(timeIntervalSince1970: $0.originalPurchaseDate.timeIntervalSince1970 + duration) - return (expirationDate, $0) - } - } else { - #if swift(>=4.1) - return receiptItems.compactMap { - if let expirationDate = $0.subscriptionExpirationDate { - return (expirationDate, $0) - } - return nil - } - #else - return receiptItems.flatMap { - if let expirationDate = $0.subscriptionExpirationDate { - return (expirationDate, $0) - } - return nil - } - #endif - } - } - - private class func getReceipts(for subscriptionType: SubscriptionType, inReceipt receipt: ReceiptInfo) -> [ReceiptInfo]? { - switch subscriptionType { - case .autoRenewable: - return receipt["latest_receipt_info"] as? [ReceiptInfo] - case .nonRenewing: - return getInAppReceipts(receipt: receipt) - } - } - - private class func getReceiptsAndDuration(for subscriptionType: SubscriptionType, inReceipt receipt: ReceiptInfo) -> ([ReceiptInfo]?, TimeInterval?) { - switch subscriptionType { - case .autoRenewable: - return (receipt["latest_receipt_info"] as? [ReceiptInfo], nil) - case .nonRenewing(let duration): - return (getInAppReceipts(receipt: receipt), duration) - } - } - - private class func getReceiptRequestDate(inReceipt receipt: ReceiptInfo) -> Date? { - - guard let receiptInfo = receipt["receipt"] as? ReceiptInfo, - let requestDateString = receiptInfo["request_date_ms"] as? String else { - return nil - } - return Date(millisecondsSince1970: requestDateString) - } - - private class func getInAppReceipts(receipt: ReceiptInfo) -> [ReceiptInfo]? { - - let appReceipt = receipt["receipt"] as? ReceiptInfo - return appReceipt?["in_app"] as? [ReceiptInfo] - } - - /** - * Get all the receipts info for a specific product - * - Parameter receipts: the receipts array to grab info from - * - Parameter productId: the product id - */ - private class func filterReceiptsInfo(receipts: [ReceiptInfo]?, withProductIds productIds: Set) -> [ReceiptInfo] { - - guard let receipts = receipts else { - return [] - } - - // Filter receipts with matching product ids - let receiptsMatchingProductIds = receipts - .filter { (receipt) -> Bool in - if let productId = receipt["product_id"] as? String { - return productIds.contains(productId) - } - return false - } - - return receiptsMatchingProductIds - } -} diff --git a/SwiftyStoreKit/InAppReceiptRefreshRequest.swift b/SwiftyStoreKit/InAppReceiptRefreshRequest.swift deleted file mode 100644 index d4402c4d..00000000 --- a/SwiftyStoreKit/InAppReceiptRefreshRequest.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// InAppReceiptRefreshRequest.swift -// SwiftyStoreKit -// -// Created by phimage on 23/12/15. -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit -import Foundation - -class InAppReceiptRefreshRequest: NSObject, SKRequestDelegate, InAppRequest { - - enum ResultType { - case success - case error(e: Error) - } - - typealias RequestCallback = (ResultType) -> Void - typealias ReceiptRefresh = (_ receiptProperties: [String: Any]?, _ callback: @escaping RequestCallback) -> InAppReceiptRefreshRequest - - class func refresh(_ receiptProperties: [String: Any]? = nil, callback: @escaping RequestCallback) -> InAppReceiptRefreshRequest { - let request = InAppReceiptRefreshRequest(receiptProperties: receiptProperties, callback: callback) - request.start() - return request - } - - let refreshReceiptRequest: SKReceiptRefreshRequest - let callback: RequestCallback - - deinit { - refreshReceiptRequest.delegate = nil - } - - init(receiptProperties: [String: Any]? = nil, callback: @escaping RequestCallback) { - self.callback = callback - self.refreshReceiptRequest = SKReceiptRefreshRequest(receiptProperties: receiptProperties) - super.init() - self.refreshReceiptRequest.delegate = self - } - - func start() { - self.refreshReceiptRequest.start() - } - - func cancel() { - self.refreshReceiptRequest.cancel() - } - - func requestDidFinish(_ request: SKRequest) { - /*if let resoreRequest = request as? SKReceiptRefreshRequest { - let receiptProperties = resoreRequest.receiptProperties ?? [:] - for (k, v) in receiptProperties { - print("\(k): \(v)") - } - }*/ - performCallback(.success) - } - func request(_ request: SKRequest, didFailWithError error: Error) { - // XXX could here check domain and error code to return typed exception - performCallback(.error(e: error)) - } - private func performCallback(_ result: ResultType) { - DispatchQueue.main.async { - self.callback(result) - } - } -} diff --git a/SwiftyStoreKit/InAppReceiptVerificator.swift b/SwiftyStoreKit/InAppReceiptVerificator.swift deleted file mode 100644 index c86ac1c8..00000000 --- a/SwiftyStoreKit/InAppReceiptVerificator.swift +++ /dev/null @@ -1,119 +0,0 @@ -// -// InAppReceiptVerificator.swift -// SwiftyStoreKit -// -// Created by Andrea Bizzotto on 16/05/2017. -// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation - -class InAppReceiptVerificator: NSObject { - - let appStoreReceiptURL: URL? - init(appStoreReceiptURL: URL? = Bundle.main.appStoreReceiptURL) { - self.appStoreReceiptURL = appStoreReceiptURL - } - - var appStoreReceiptData: Data? { - guard let receiptDataURL = appStoreReceiptURL, - let data = try? Data(contentsOf: receiptDataURL) else { - return nil - } - return data - } - - private var receiptRefreshRequest: InAppReceiptRefreshRequest? - - /** - * Verify application receipt. - * - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format - * - Parameter forceRefresh: If true, refreshes the receipt even if one already exists. - * - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability) - * - Parameter completion: handler for result - */ - @discardableResult - public func verifyReceipt(using validator: ReceiptValidator, - forceRefresh: Bool, - refresh: InAppReceiptRefreshRequest.ReceiptRefresh = InAppReceiptRefreshRequest.refresh, - completion: @escaping (VerifyReceiptResult) -> Void) -> InAppRequest? { - - return fetchReceipt(forceRefresh: forceRefresh, refresh: refresh) { result in - switch result { - case .success(let receiptData): - self.verify(receiptData: receiptData, using: validator, completion: completion) - case .error(let error): - completion(.error(error: error)) - } - } - } - - /** - * Fetch application receipt. This method does two things: - * * If the receipt is missing, refresh it - * * If the receipt is available or is refreshed, validate it - * - Parameter forceRefresh: If true, refreshes the receipt even if one already exists. - * - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability) - * - Parameter completion: handler for result - */ - @discardableResult - public func fetchReceipt(forceRefresh: Bool, - refresh: InAppReceiptRefreshRequest.ReceiptRefresh = InAppReceiptRefreshRequest.refresh, - completion: @escaping (FetchReceiptResult) -> Void) -> InAppRequest? { - - if let receiptData = appStoreReceiptData, forceRefresh == false { - completion(.success(receiptData: receiptData)) - return nil - } else { - - receiptRefreshRequest = refresh(nil) { result in - - self.receiptRefreshRequest = nil - - switch result { - case .success: - if let receiptData = self.appStoreReceiptData { - completion(.success(receiptData: receiptData)) - } else { - completion(.error(error: .noReceiptData)) - } - case .error(let e): - completion(.error(error: .networkError(error: e))) - } - } - return receiptRefreshRequest - } - } - - /** - * - Parameter receiptData: encrypted receipt data - * - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format - * - Parameter completion: handler for result - */ - private func verify(receiptData: Data, using validator: ReceiptValidator, completion: @escaping (VerifyReceiptResult) -> Void) { - - validator.validate(receiptData: receiptData) { result in - - DispatchQueue.main.async { - completion(result) - } - } - } -} diff --git a/SwiftyStoreKit/OS.swift b/SwiftyStoreKit/OS.swift deleted file mode 100644 index 69c54ab8..00000000 --- a/SwiftyStoreKit/OS.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// OS.swift -// SwiftyStoreKit -// -// Copyright (c) 2020 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit - -// MARK: - Missing SKMutablePayment init with product on macOS -#if os(OSX) - extension SKMutablePayment { - convenience init(product: SKProduct) { - self.init() - self.productIdentifier = product.productIdentifier - } - } -#endif - -// MARK: - Missing SKError on watchOS -#if os(watchOS) && swift(<5.3) -public struct SKError: Error { - - public typealias Code = SKErrorCode - - let _nsError: NSError - - init(_nsError: NSError) { - self._nsError = _nsError - } - - var code: Code { - return Code(rawValue: _nsError.code) ?? .unknown - } - - static var unknown: Code = .unknown - static var paymentInvalid: Code = .paymentInvalid -} -#endif diff --git a/SwiftyStoreKit/PaymentQueueController.swift b/SwiftyStoreKit/PaymentQueueController.swift deleted file mode 100644 index 758dafd2..00000000 --- a/SwiftyStoreKit/PaymentQueueController.swift +++ /dev/null @@ -1,261 +0,0 @@ -// -// PaymentQueueController.swift -// SwiftyStoreKit -// -// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation -import StoreKit - -protocol TransactionController { - - /// Process the supplied transactions on a given queue. - /// - parameter transactions: transactions to process - /// - parameter paymentQueue: payment queue for finishing transactions - /// - returns: array of unhandled transactions - func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] -} - -public enum TransactionResult { - case purchased(purchase: PurchaseDetails) - case restored(purchase: Purchase) - case failed(error: SKError) -} - -public protocol PaymentQueue: class { - - func add(_ observer: SKPaymentTransactionObserver) - func remove(_ observer: SKPaymentTransactionObserver) - - func add(_ payment: SKPayment) - - func start(_ downloads: [SKDownload]) - func pause(_ downloads: [SKDownload]) - func resume(_ downloads: [SKDownload]) - func cancel(_ downloads: [SKDownload]) - - func restoreCompletedTransactions(withApplicationUsername username: String?) - - func finishTransaction(_ transaction: SKPaymentTransaction) -} - -extension SKPaymentQueue: PaymentQueue { - #if os(watchOS) && swift(<5.3) - public func resume(_ downloads: [SKDownload]) { - resumeDownloads(downloads) - } - #endif -} - -extension SKPaymentTransaction { - - open override var debugDescription: String { - let transactionId = transactionIdentifier ?? "null" - return "productId: \(payment.productIdentifier), transactionId: \(transactionId), state: \(transactionState), date: \(String(describing: transactionDate))" - } -} - -extension SKPaymentTransactionState: CustomDebugStringConvertible { - - public var debugDescription: String { - - switch self { - case .purchasing: return "purchasing" - case .purchased: return "purchased" - case .failed: return "failed" - case .restored: return "restored" - case .deferred: return "deferred" - @unknown default: return "default" - } - } -} - -class PaymentQueueController: NSObject, SKPaymentTransactionObserver { - - private let paymentsController: PaymentsController - - private let restorePurchasesController: RestorePurchasesController - - private let completeTransactionsController: CompleteTransactionsController - - unowned let paymentQueue: PaymentQueue - - deinit { - paymentQueue.remove(self) - } - - init(paymentQueue: PaymentQueue = SKPaymentQueue.default(), - paymentsController: PaymentsController = PaymentsController(), - restorePurchasesController: RestorePurchasesController = RestorePurchasesController(), - completeTransactionsController: CompleteTransactionsController = CompleteTransactionsController()) { - - self.paymentQueue = paymentQueue - self.paymentsController = paymentsController - self.restorePurchasesController = restorePurchasesController - self.completeTransactionsController = completeTransactionsController - super.init() - paymentQueue.add(self) - } - - private func assertCompleteTransactionsWasCalled() { - - let message = "SwiftyStoreKit.completeTransactions() must be called when the app launches." - assert(completeTransactionsController.completeTransactions != nil, message) - } - - func startPayment(_ payment: Payment) { - assertCompleteTransactionsWasCalled() - - let skPayment = SKMutablePayment(product: payment.product) - skPayment.applicationUsername = payment.applicationUsername - skPayment.quantity = payment.quantity - - if #available(iOS 12.2, tvOS 12.2, OSX 10.14.4, watchOS 6.2, *) { - if let discount = payment.paymentDiscount?.discount as? SKPaymentDiscount { - skPayment.paymentDiscount = discount - } - } - - #if os(iOS) || os(tvOS) || os(watchOS) - if #available(iOS 8.3, watchOS 6.2, *) { - skPayment.simulatesAskToBuyInSandbox = payment.simulatesAskToBuyInSandbox - } - #endif - - paymentQueue.add(skPayment) - - paymentsController.append(payment) - } - - func restorePurchases(_ restorePurchases: RestorePurchases) { - assertCompleteTransactionsWasCalled() - - if restorePurchasesController.restorePurchases != nil { - return - } - - paymentQueue.restoreCompletedTransactions(withApplicationUsername: restorePurchases.applicationUsername) - - restorePurchasesController.restorePurchases = restorePurchases - } - - func completeTransactions(_ completeTransactions: CompleteTransactions) { - - guard completeTransactionsController.completeTransactions == nil else { - print("SwiftyStoreKit.completeTransactions() should only be called once when the app launches. Ignoring this call") - return - } - - completeTransactionsController.completeTransactions = completeTransactions - } - - func finishTransaction(_ transaction: PaymentTransaction) { - guard let skTransaction = transaction as? SKPaymentTransaction else { - print("Object is not a SKPaymentTransaction: \(transaction)") - return - } - paymentQueue.finishTransaction(skTransaction) - } - - func start(_ downloads: [SKDownload]) { - paymentQueue.start(downloads) - } - func pause(_ downloads: [SKDownload]) { - paymentQueue.pause(downloads) - } - - func resume(_ downloads: [SKDownload]) { - paymentQueue.resume(downloads) - } - func cancel(_ downloads: [SKDownload]) { - paymentQueue.cancel(downloads) - } - - var shouldAddStorePaymentHandler: ShouldAddStorePaymentHandler? - var updatedDownloadsHandler: UpdatedDownloadsHandler? - - // MARK: SKPaymentTransactionObserver - func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { - - /* - * Some notes about how requests are processed by SKPaymentQueue: - * - * SKPaymentQueue is used to queue payments or restore purchases requests. - * Payments are processed serially and in-order and require user interaction. - * Restore purchases requests don't require user interaction and can jump ahead of the queue. - * SKPaymentQueue rejects multiple restore purchases calls. - * Having one payment queue observer for each request causes extra processing - * Failed transactions only ever belong to queued payment requests. - * restoreCompletedTransactionsFailedWithError is always called when a restore purchases request fails. - * paymentQueueRestoreCompletedTransactionsFinished is always called following 0 or more update transactions when a restore purchases request succeeds. - * A complete transactions handler is require to catch any transactions that are updated when the app is not running. - * Registering a complete transactions handler when the app launches ensures that any pending transactions can be cleared. - * If a complete transactions handler is missing, pending transactions can be mis-attributed to any new incoming payments or restore purchases. - * - * The order in which transaction updates are processed is: - * 1. payments (transactionState: .purchased and .failed for matching product identifiers) - * 2. restore purchases (transactionState: .restored, or restoreCompletedTransactionsFailedWithError, or paymentQueueRestoreCompletedTransactionsFinished) - * 3. complete transactions (transactionState: .purchased, .failed, .restored, .deferred) - * Any transactions where state == .purchasing are ignored. - */ - var unhandledTransactions = transactions.filter { $0.transactionState != .purchasing } - - if unhandledTransactions.count > 0 { - - unhandledTransactions = paymentsController.processTransactions(transactions, on: paymentQueue) - - unhandledTransactions = restorePurchasesController.processTransactions(unhandledTransactions, on: paymentQueue) - - unhandledTransactions = completeTransactionsController.processTransactions(unhandledTransactions, on: paymentQueue) - - if unhandledTransactions.count > 0 { - let strings = unhandledTransactions.map { $0.debugDescription }.joined(separator: "\n") - print("unhandledTransactions:\n\(strings)") - } - } - } - - func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) { - - } - - func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) { - - restorePurchasesController.restoreCompletedTransactionsFailed(withError: error) - } - - func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { - - restorePurchasesController.restoreCompletedTransactionsFinished() - } - - func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) { - - updatedDownloadsHandler?(downloads) - } - - #if os(iOS) && !targetEnvironment(macCatalyst) - func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool { - - return shouldAddStorePaymentHandler?(payment, product) ?? false - } - #endif -} diff --git a/SwiftyStoreKit/PaymentsController.swift b/SwiftyStoreKit/PaymentsController.swift deleted file mode 100644 index b57c81d7..00000000 --- a/SwiftyStoreKit/PaymentsController.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// PaymentsController.swift -// SwiftyStoreKit -// -// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation -import StoreKit - -struct Payment: Hashable { - let product: SKProduct - - let paymentDiscount: PaymentDiscount? - let quantity: Int - let atomically: Bool - let applicationUsername: String - let simulatesAskToBuyInSandbox: Bool - let callback: (TransactionResult) -> Void - - func hash(into hasher: inout Hasher) { - hasher.combine(product) - hasher.combine(quantity) - hasher.combine(atomically) - hasher.combine(applicationUsername) - hasher.combine(simulatesAskToBuyInSandbox) - } - - static func == (lhs: Payment, rhs: Payment) -> Bool { - return lhs.product.productIdentifier == rhs.product.productIdentifier - } -} - -public struct PaymentDiscount { - let discount: AnyObject? - - @available(iOS 12.2, tvOS 12.2, OSX 10.14.4, watchOS 6.2, macCatalyst 13.0, *) - public init(discount: SKPaymentDiscount) { - self.discount = discount - } - - private init() { - self.discount = nil - } -} - -class PaymentsController: TransactionController { - - private var payments: [Payment] = [] - - private func findPaymentIndex(withProductIdentifier identifier: String) -> Int? { - for payment in payments where payment.product.productIdentifier == identifier { - return payments.firstIndex(of: payment) - } - return nil - } - - func hasPayment(_ payment: Payment) -> Bool { - return findPaymentIndex(withProductIdentifier: payment.product.productIdentifier) != nil - } - - func append(_ payment: Payment) { - payments.append(payment) - } - - func processTransaction(_ transaction: SKPaymentTransaction, on paymentQueue: PaymentQueue) -> Bool { - - let transactionProductIdentifier = transaction.payment.productIdentifier - - guard let paymentIndex = findPaymentIndex(withProductIdentifier: transactionProductIdentifier) else { - - return false - } - let payment = payments[paymentIndex] - - let transactionState = transaction.transactionState - - if transactionState == .purchased { - let purchase = PurchaseDetails(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, product: payment.product, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !payment.atomically) - - payment.callback(.purchased(purchase: purchase)) - - if payment.atomically { - paymentQueue.finishTransaction(transaction) - } - payments.remove(at: paymentIndex) - return true - } - - if transactionState == .restored { - print("Unexpected restored transaction for payment \(transactionProductIdentifier)") - - let purchase = PurchaseDetails(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, product: payment.product, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !payment.atomically) - - payment.callback(.purchased(purchase: purchase)) - - if payment.atomically { - paymentQueue.finishTransaction(transaction) - } - payments.remove(at: paymentIndex) - return true - } - - if transactionState == .failed { - - payment.callback(.failed(error: transactionError(for: transaction.error as NSError?))) - - paymentQueue.finishTransaction(transaction) - payments.remove(at: paymentIndex) - return true - } - - return false - } - - func transactionError(for error: NSError?) -> SKError { - let message = "Unknown error" - let altError = NSError(domain: SKErrorDomain, code: SKError.unknown.rawValue, userInfo: [ NSLocalizedDescriptionKey: message ]) - let nsError = error ?? altError - return SKError(_nsError: nsError) - } - - func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] { - - return transactions.filter { !processTransaction($0, on: paymentQueue) } - } -} diff --git a/SwiftyStoreKit/ProductsInfoController.swift b/SwiftyStoreKit/ProductsInfoController.swift deleted file mode 100644 index 591e26a1..00000000 --- a/SwiftyStoreKit/ProductsInfoController.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// ProductsInfoController.swift -// SwiftyStoreKit -// -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation -import StoreKit - -protocol InAppProductRequestBuilder: class { - func request(productIds: Set, callback: @escaping InAppProductRequestCallback) -> InAppProductRequest -} - -class InAppProductQueryRequestBuilder: InAppProductRequestBuilder { - - func request(productIds: Set, callback: @escaping InAppProductRequestCallback) -> InAppProductRequest { - return InAppProductQueryRequest(productIds: productIds, callback: callback) - } -} - -class ProductsInfoController: NSObject { - - struct InAppProductQuery { - let request: InAppProductRequest - var completionHandlers: [InAppProductRequestCallback] - } - - let inAppProductRequestBuilder: InAppProductRequestBuilder - init(inAppProductRequestBuilder: InAppProductRequestBuilder = InAppProductQueryRequestBuilder()) { - self.inAppProductRequestBuilder = inAppProductRequestBuilder - } - - // As we can have multiple inflight requests, we store them in a dictionary by product ids - private var inflightRequests: [Set: InAppProductQuery] = [:] - - @discardableResult - func retrieveProductsInfo(_ productIds: Set, completion: @escaping (RetrieveResults) -> Void) -> InAppProductRequest { - - if inflightRequests[productIds] == nil { - let request = inAppProductRequestBuilder.request(productIds: productIds) { results in - - if let query = self.inflightRequests[productIds] { - for completion in query.completionHandlers { - completion(results) - } - self.inflightRequests[productIds] = nil - } else { - // should not get here, but if it does it seems reasonable to call the outer completion block - completion(results) - } - } - inflightRequests[productIds] = InAppProductQuery(request: request, completionHandlers: [completion]) - request.start() - return request - } else { - inflightRequests[productIds]!.completionHandlers.append(completion) - return inflightRequests[productIds]!.request - } - } -} diff --git a/SwiftyStoreKit/RestorePurchasesController.swift b/SwiftyStoreKit/RestorePurchasesController.swift deleted file mode 100644 index 4e37414d..00000000 --- a/SwiftyStoreKit/RestorePurchasesController.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// RestorePurchasesController.swift -// SwiftyStoreKit -// -// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import Foundation -import StoreKit - -struct RestorePurchases { - let atomically: Bool - let applicationUsername: String? - let callback: ([TransactionResult]) -> Void - - init(atomically: Bool, applicationUsername: String? = nil, callback: @escaping ([TransactionResult]) -> Void) { - self.atomically = atomically - self.applicationUsername = applicationUsername - self.callback = callback - } -} - -class RestorePurchasesController: TransactionController { - - public var restorePurchases: RestorePurchases? - - private var restoredPurchases: [TransactionResult] = [] - - func processTransaction(_ transaction: SKPaymentTransaction, atomically: Bool, on paymentQueue: PaymentQueue) -> Purchase? { - - let transactionState = transaction.transactionState - - if transactionState == .restored { - - let transactionProductIdentifier = transaction.payment.productIdentifier - - let purchase = Purchase(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !atomically) - if atomically { - paymentQueue.finishTransaction(transaction) - } - return purchase - } - return nil - } - - func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] { - - guard let restorePurchases = restorePurchases else { - return transactions - } - - var unhandledTransactions: [SKPaymentTransaction] = [] - for transaction in transactions { - if let restoredPurchase = processTransaction(transaction, atomically: restorePurchases.atomically, on: paymentQueue) { - restoredPurchases.append(.restored(purchase: restoredPurchase)) - } else { - unhandledTransactions.append(transaction) - } - } - - return unhandledTransactions - } - - func restoreCompletedTransactionsFailed(withError error: Error) { - - guard let restorePurchases = restorePurchases else { - print("Callback already called. Returning") - return - } - restoredPurchases.append(.failed(error: SKError(_nsError: error as NSError))) - restorePurchases.callback(restoredPurchases) - - // Reset state after error received - restoredPurchases = [] - self.restorePurchases = nil - - } - - func restoreCompletedTransactionsFinished() { - - guard let restorePurchases = restorePurchases else { - print("Callback already called. Returning") - return - } - restorePurchases.callback(restoredPurchases) - - // Reset state after error transactions finished - restoredPurchases = [] - self.restorePurchases = nil - } -} diff --git a/SwiftyStoreKit/SKProduct+LocalizedPrice.swift b/SwiftyStoreKit/SKProduct+LocalizedPrice.swift deleted file mode 100644 index 693db524..00000000 --- a/SwiftyStoreKit/SKProduct+LocalizedPrice.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// SKProduct+LocalizedPrice.swift -// SwiftyStoreKit -// -// Created by Andrea Bizzotto on 19/10/2016. -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit - -public extension SKProduct { - - var localizedPrice: String? { - return priceFormatter(locale: priceLocale).string(from: price) - } - - private func priceFormatter(locale: Locale) -> NumberFormatter { - let formatter = NumberFormatter() - formatter.locale = locale - formatter.numberStyle = .currency - return formatter - } - - @available(iOSApplicationExtension 11.2, iOS 11.2, OSX 10.13.2, tvOS 11.2, watchOS 6.2, macCatalyst 13.0, *) - var localizedSubscriptionPeriod: String { - guard let subscriptionPeriod = self.subscriptionPeriod else { return "" } - - let dateComponents: DateComponents - - switch subscriptionPeriod.unit { - case .day: dateComponents = DateComponents(day: subscriptionPeriod.numberOfUnits) - case .week: dateComponents = DateComponents(weekOfMonth: subscriptionPeriod.numberOfUnits) - case .month: dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits) - case .year: dateComponents = DateComponents(year: subscriptionPeriod.numberOfUnits) - @unknown default: - print("WARNING: SwiftyStoreKit localizedSubscriptionPeriod does not handle all SKProduct.PeriodUnit cases.") - // Default to month units in the unlikely event a different unit type is added to a future OS version - dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits) - } - - return DateComponentsFormatter.localizedString(from: dateComponents, unitsStyle: .short) ?? "" - } - -} diff --git a/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift b/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift deleted file mode 100644 index eddb7b7a..00000000 --- a/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// SKProductDiscount+LocalizedPrice.swift -// SwiftyStoreKit -// -// Created by Sam Spencer on 5/29/20. -// Copyright © 2020 Sam Spencer. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit - -@available(iOSApplicationExtension 11.2, iOS 11.2, OSX 10.13.2, tvOS 11.2, watchOS 4.2, macCatalyst 13.0, *) -public extension SKProductDiscount { - - /// The formatted discount price of the product using the local currency. - var localizedPrice: String? { - return priceFormatter(locale: priceLocale).string(from: price) - } - - private func priceFormatter(locale: Locale) -> NumberFormatter { - let formatter = NumberFormatter() - formatter.locale = locale - formatter.numberStyle = .currency - return formatter - } - - /// The formatted, localized period / date for the product discount. - /// - note: The subscription period for the discount is independent of the product's regular subscription period, and does not have to match in units or duration. - var localizedSubscriptionPeriod: String { - let dateComponents: DateComponents - - switch subscriptionPeriod.unit { - case .day: dateComponents = DateComponents(day: subscriptionPeriod.numberOfUnits) - case .week: dateComponents = DateComponents(weekOfMonth: subscriptionPeriod.numberOfUnits) - case .month: dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits) - case .year: dateComponents = DateComponents(year: subscriptionPeriod.numberOfUnits) - @unknown default: - print("WARNING: SwiftyStoreKit localizedSubscriptionPeriod does not handle all SKProduct.PeriodUnit cases.") - // Default to month units in the unlikely event a different unit type is added to a future OS version - dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits) - } - - return DateComponentsFormatter.localizedString(from: dateComponents, unitsStyle: .full) ?? "" - } - -} - diff --git a/SwiftyStoreKit/SwiftyStoreKit+Types.swift b/SwiftyStoreKit/SwiftyStoreKit+Types.swift deleted file mode 100644 index 8eea5c9b..00000000 --- a/SwiftyStoreKit/SwiftyStoreKit+Types.swift +++ /dev/null @@ -1,332 +0,0 @@ -// -// SwiftyStoreKit+Types.swift -// SwiftyStoreKit -// -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit - -// MARK: Purchases - -/// The Purchased protocol allows different purchase flows to be handled by common code in simple cases -/// -/// For example you could route through to -/// -/// func didPurchase(item:P) { ... } -/// -/// for example -/// - SwiftyStoreKit.completeTransactions (in .purchased and .restored cases) -/// - SwiftyStoreKit.restorePurchases (for results.restoredPurchases) -/// - SwiftyStoreKit.purchaseProducd (in .success case) -public protocol Purchased { - var productId: String { get } - var quantity: Int { get } - var originalPurchaseDate: Date { get } -} - -extension Purchase: Purchased { - public var originalPurchaseDate: Date { - guard let date = originalTransaction?.transactionDate ?? transaction.transactionDate else { - fatalError("there should always be a transaction date, so this should not happen...") - } - return date - } -} - -extension PurchaseDetails: Purchased { - public var originalPurchaseDate: Date { - guard let date = originalTransaction?.transactionDate ?? transaction.transactionDate else { - fatalError("there should always be a transaction date, so this should not happen...") - } - return date - } -} - -// Restored product -public struct Purchase { - public let productId: String - public let quantity: Int - public let transaction: PaymentTransaction - public let originalTransaction: PaymentTransaction? - public let needsFinishTransaction: Bool - - public init(productId: String, quantity: Int, transaction: PaymentTransaction, originalTransaction: PaymentTransaction?, needsFinishTransaction: Bool) { - self.productId = productId - self.quantity = quantity - self.transaction = transaction - self.originalTransaction = originalTransaction - self.needsFinishTransaction = needsFinishTransaction - } -} - -/// Purchased product -public struct PurchaseDetails { - public let productId: String - public let quantity: Int - public let product: SKProduct - public let transaction: PaymentTransaction - public let originalTransaction: PaymentTransaction? - public let needsFinishTransaction: Bool - - public init(productId: String, quantity: Int, product: SKProduct, transaction: PaymentTransaction, originalTransaction: PaymentTransaction?, needsFinishTransaction: Bool) { - self.productId = productId - self.quantity = quantity - self.product = product - self.transaction = transaction - self.originalTransaction = originalTransaction - self.needsFinishTransaction = needsFinishTransaction - } -} - -/// Conform to this protocol to provide custom receipt validator -public protocol ReceiptValidator { - func validate(receiptData: Data, completion: @escaping (VerifyReceiptResult) -> Void) -} - -/// Payment transaction -public protocol PaymentTransaction { - var transactionDate: Date? { get } - var transactionState: SKPaymentTransactionState { get } - var transactionIdentifier: String? { get } - var downloads: [SKDownload] { get } -} - -/// Add PaymentTransaction conformance to SKPaymentTransaction -extension SKPaymentTransaction: PaymentTransaction { } - -/// Products information -public struct RetrieveResults { - public let retrievedProducts: Set - public let invalidProductIDs: Set - public let error: Error? - - public init(retrievedProducts: Set, invalidProductIDs: Set, error: Error?) { - self.retrievedProducts = retrievedProducts - self.invalidProductIDs = invalidProductIDs - self.error = error - } -} - -/// Purchase result -public enum PurchaseResult { - case success(purchase: PurchaseDetails) - case error(error: SKError) -} - -/// Restore purchase results -public struct RestoreResults { - public let restoredPurchases: [Purchase] - public let restoreFailedPurchases: [(SKError, String?)] - - public init(restoredPurchases: [Purchase], restoreFailedPurchases: [(SKError, String?)]) { - self.restoredPurchases = restoredPurchases - self.restoreFailedPurchases = restoreFailedPurchases - } -} - -public typealias ShouldAddStorePaymentHandler = (_ payment: SKPayment, _ product: SKProduct) -> Bool -public typealias UpdatedDownloadsHandler = (_ downloads: [SKDownload]) -> Void - -// MARK: Receipt verification - -/// Info for receipt returned by server -public typealias ReceiptInfo = [String: AnyObject] - -/// Fetch receipt result -public enum FetchReceiptResult { - case success(receiptData: Data) - case error(error: ReceiptError) -} - -/// Verify receipt result -public enum VerifyReceiptResult { - case success(receipt: ReceiptInfo) - case error(error: ReceiptError) -} - -/// Result for Consumable and NonConsumable -public enum VerifyPurchaseResult { - case purchased(item: ReceiptItem) - case notPurchased -} - -/// Verify subscription result -public enum VerifySubscriptionResult { - case purchased(expiryDate: Date, items: [ReceiptItem]) - case expired(expiryDate: Date, items: [ReceiptItem]) - case notPurchased -} - -public enum SubscriptionType { - case autoRenewable - case nonRenewing(validDuration: TimeInterval) -} - -public struct ReceiptItem: Purchased, Codable { - - /// The product identifier of the item that was purchased. This value corresponds to the `productIdentifier` property of the `SKPayment` object stored in the transaction’s payment property. - public var productId: String - - /// The number of items purchased. This value corresponds to the `quantity` property of the `SKPayment` object stored in the transaction’s payment property. - public var quantity: Int - - /// The transaction identifier of the item that was purchased. This value corresponds to the transaction’s `transactionIdentifier` property. - public var transactionId: String - - /// For a transaction that restores a previous transaction, the transaction identifier of the original transaction. - /// - /// Otherwise, identical to the transaction identifier. This value corresponds to the original transaction’s `transactionIdentifier` property. All receipts in a chain of renewals for an auto-renewable subscription have the same value for this field. - public var originalTransactionId: String - - /// The date and time that the item was purchased. This value corresponds to the transaction’s `transactionDate` property. - public var purchaseDate: Date - - /// For a transaction that restores a previous transaction, the date of the original transaction. This value corresponds to the original transaction’s `transactionDate` property. In an auto-renewable subscription receipt, this indicates the beginning of the subscription period, even if the subscription has been renewed. - public var originalPurchaseDate: Date - - /// The primary key for identifying subscription purchases. - public var webOrderLineItemId: String? - - /// The expiration date for the subscription, expressed as the number of milliseconds since January 1, 1970, 00:00:00 GMT. This key is **only** present for **auto-renewable** subscription receipts. - public var subscriptionExpirationDate: Date? - - /// For a transaction that was canceled by Apple customer support, the time and date of the cancellation. - /// - /// Treat a canceled receipt the same as if no purchase had ever been made. - public var cancellationDate: Date? - - /// Indicates whether or not the subscription item is currently within a given trial period. - public var isTrialPeriod: Bool - - /// Indicates whether or not the subscription item is currently within an intro offer period. - public var isInIntroOfferPeriod: Bool - - public init(productId: String, quantity: Int, transactionId: String, originalTransactionId: String, purchaseDate: Date, originalPurchaseDate: Date, webOrderLineItemId: String?, subscriptionExpirationDate: Date?, cancellationDate: Date?, isTrialPeriod: Bool, isInIntroOfferPeriod: Bool) { - self.productId = productId - self.quantity = quantity - self.transactionId = transactionId - self.originalTransactionId = originalTransactionId - self.purchaseDate = purchaseDate - self.originalPurchaseDate = originalPurchaseDate - self.webOrderLineItemId = webOrderLineItemId - self.subscriptionExpirationDate = subscriptionExpirationDate - self.cancellationDate = cancellationDate - self.isTrialPeriod = isTrialPeriod - self.isInIntroOfferPeriod = isInIntroOfferPeriod - } -} - -/// Error when managing receipt -public enum ReceiptError: Swift.Error { - /// No receipt data - case noReceiptData - /// No data received - case noRemoteData - /// Error when encoding HTTP body into JSON - case requestBodyEncodeError(error: Swift.Error) - /// Error when proceeding request - case networkError(error: Swift.Error) - /// Error when decoding response - case jsonDecodeError(string: String?) - /// Receive invalid - bad status returned - case receiptInvalid(receipt: ReceiptInfo, status: ReceiptStatus) -} - -/// Status code returned by remote server -/// -/// See Table 2-1 Status codes -public enum ReceiptStatus: Int { - /// Not decodable status - case unknown = -2 - /// No status returned - case none = -1 - /// valid statua - case valid = 0 - /// The App Store could not read the JSON object you provided. - case jsonNotReadable = 21000 - /// The data in the receipt-data property was malformed or missing. - case malformedOrMissingData = 21002 - /// The receipt could not be authenticated. - case receiptCouldNotBeAuthenticated = 21003 - /// The shared secret you provided does not match the shared secret on file for your account. - case secretNotMatching = 21004 - /// The receipt server is not currently available. - case receiptServerUnavailable = 21005 - /// This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response. - case subscriptionExpired = 21006 - /// This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead. - case testReceipt = 21007 - /// This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead. - case productionEnvironment = 21008 - - var isValid: Bool { return self == .valid} -} - -// Receipt field as defined in : https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1 -public enum ReceiptInfoField: String { - /// Bundle Identifier. This corresponds to the value of CFBundleIdentifier in the Info.plist file. - case bundle_id - /// The app’s version number.This corresponds to the value of CFBundleVersion (in iOS) or CFBundleShortVersionString (in OS X) in the Info.plist. - case application_version - /// The version of the app that was originally purchased. This corresponds to the value of CFBundleVersion (in iOS) or CFBundleShortVersionString (in OS X) in the Info.plist file when the purchase was originally made. - case original_application_version - /// The date when the app receipt was created. - case creation_date - /// The date that the app receipt expires. This key is present only for apps purchased through the Volume Purchase Program. - case expiration_date - - /// The receipt for an in-app purchase. - case in_app - - public enum InApp: String { - /// The number of items purchased. This value corresponds to the quantity property of the SKPayment object stored in the transaction’s payment property. - case quantity - /// The product identifier of the item that was purchased. This value corresponds to the productIdentifier property of the SKPayment object stored in the transaction’s payment property. - case product_id - /// The transaction identifier of the item that was purchased. This value corresponds to the transaction’s transactionIdentifier property. - case transaction_id - /// For a transaction that restores a previous transaction, the transaction identifier of the original transaction. Otherwise, identical to the transaction identifier. This value corresponds to the original transaction’s transactionIdentifier property. All receipts in a chain of renewals for an auto-renewable subscription have the same value for this field. - case original_transaction_id - /// The date and time that the item was purchased. This value corresponds to the transaction’s transactionDate property. - case purchase_date - /// For a transaction that restores a previous transaction, the date of the original transaction. This value corresponds to the original transaction’s transactionDate property. In an auto-renewable subscription receipt, this indicates the beginning of the subscription period, even if the subscription has been renewed. - case original_purchase_date - /// The expiration date for the subscription, expressed as the number of milliseconds since January 1, 1970, 00:00:00 GMT. This key is only present for auto-renewable subscription receipts. - case expires_date - /// For a transaction that was canceled by Apple customer support, the time and date of the cancellation. Treat a canceled receipt the same as if no purchase had ever been made. - case cancellation_date - #if os(iOS) || os(tvOS) - /// A string that the App Store uses to uniquely identify the application that created the transaction. If your server supports multiple applications, you can use this value to differentiate between them. Apps are assigned an identifier only in the production environment, so this key is not present for receipts created in the test environment. This field is not present for Mac apps. See also Bundle Identifier. - case app_item_id - #endif - /// An arbitrary number that uniquely identifies a revision of your application. This key is not present for receipts created in the test environment. - case version_external_identifier - /// The primary key for identifying subscription purchases. - case web_order_line_item_id - } -} - -#if os(OSX) - public enum ReceiptExitCode: Int32 { - /// If validation fails in OS X, call exit with a status of 173. This exit status notifies the system that your application has determined that its receipt is invalid. At this point, the system attempts to obtain a valid receipt and may prompt for the user’s iTunes credentials - case notValid = 173 - } -#endif diff --git a/SwiftyStoreKit/SwiftyStoreKit.swift b/SwiftyStoreKit/SwiftyStoreKit.swift deleted file mode 100644 index 7e51a14e..00000000 --- a/SwiftyStoreKit/SwiftyStoreKit.swift +++ /dev/null @@ -1,312 +0,0 @@ -// -// SwiftyStoreKit.swift -// SwiftyStoreKit -// -// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import StoreKit - -public class SwiftyStoreKit { - - private let productsInfoController: ProductsInfoController - - fileprivate let paymentQueueController: PaymentQueueController - - fileprivate let receiptVerificator: InAppReceiptVerificator - - init(productsInfoController: ProductsInfoController = ProductsInfoController(), - paymentQueueController: PaymentQueueController = PaymentQueueController(paymentQueue: SKPaymentQueue.default()), - receiptVerificator: InAppReceiptVerificator = InAppReceiptVerificator()) { - - self.productsInfoController = productsInfoController - self.paymentQueueController = paymentQueueController - self.receiptVerificator = receiptVerificator - } - - // MARK: private methods - fileprivate func retrieveProductsInfo(_ productIds: Set, completion: @escaping (RetrieveResults) -> Void) -> InAppProductRequest { - return productsInfoController.retrieveProductsInfo(productIds, completion: completion) - } - - fileprivate func purchaseProduct(_ productId: String, quantity: Int = 1, atomically: Bool = true, applicationUsername: String = "", simulatesAskToBuyInSandbox: Bool = false, completion: @escaping ( PurchaseResult) -> Void) -> InAppProductRequest { - - return retrieveProductsInfo(Set([productId])) { result -> Void in - if let product = result.retrievedProducts.first { - self.purchase(product: product, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox, completion: completion) - } else if let error = result.error { - completion(.error(error: SKError(_nsError: error as NSError))) - } else if let invalidProductId = result.invalidProductIDs.first { - let userInfo = [ NSLocalizedDescriptionKey: "Invalid product id: \(invalidProductId)" ] - let error = NSError(domain: SKErrorDomain, code: SKError.paymentInvalid.rawValue, userInfo: userInfo) - completion(.error(error: SKError(_nsError: error))) - } else { - let error = NSError(domain: SKErrorDomain, code: SKError.unknown.rawValue, userInfo: nil) - completion(.error(error: SKError(_nsError: error))) - } - } - } - - fileprivate func purchase(product: SKProduct, quantity: Int, atomically: Bool, applicationUsername: String = "", simulatesAskToBuyInSandbox: Bool = false, paymentDiscount: PaymentDiscount? = nil, completion: @escaping (PurchaseResult) -> Void) { - paymentQueueController.startPayment(Payment(product: product, paymentDiscount: paymentDiscount, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox) { result in - - completion(self.processPurchaseResult(result)) - }) - } - - fileprivate func restorePurchases(atomically: Bool = true, applicationUsername: String = "", completion: @escaping (RestoreResults) -> Void) { - - paymentQueueController.restorePurchases(RestorePurchases(atomically: atomically, applicationUsername: applicationUsername) { results in - - let results = self.processRestoreResults(results) - completion(results) - }) - } - - fileprivate func completeTransactions(atomically: Bool = true, completion: @escaping ([Purchase]) -> Void) { - - paymentQueueController.completeTransactions(CompleteTransactions(atomically: atomically, callback: completion)) - } - - fileprivate func finishTransaction(_ transaction: PaymentTransaction) { - - paymentQueueController.finishTransaction(transaction) - } - - private func processPurchaseResult(_ result: TransactionResult) -> PurchaseResult { - switch result { - case .purchased(let purchase): - return .success(purchase: purchase) - case .failed(let error): - return .error(error: error) - case .restored(let purchase): - return .error(error: storeInternalError(description: "Cannot restore product \(purchase.productId) from purchase path")) - } - } - - private func processRestoreResults(_ results: [TransactionResult]) -> RestoreResults { - var restoredPurchases: [Purchase] = [] - var restoreFailedPurchases: [(SKError, String?)] = [] - for result in results { - switch result { - case .purchased(let purchase): - let error = storeInternalError(description: "Cannot purchase product \(purchase.productId) from restore purchases path") - restoreFailedPurchases.append((error, purchase.productId)) - case .failed(let error): - restoreFailedPurchases.append((error, nil)) - case .restored(let purchase): - restoredPurchases.append(purchase) - } - } - return RestoreResults(restoredPurchases: restoredPurchases, restoreFailedPurchases: restoreFailedPurchases) - } - - private func storeInternalError(code: SKError.Code = SKError.unknown, description: String = "") -> SKError { - let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ]) - return SKError(_nsError: error) - } -} - -extension SwiftyStoreKit { - - // MARK: Singleton - fileprivate static let sharedInstance = SwiftyStoreKit() - - // MARK: Public methods - Purchases - - /// Check if the current device can make payments. - /// - returns: `false` if this device is not able or allowed to make payments - public class var canMakePayments: Bool { - return SKPaymentQueue.canMakePayments() - } - - /// Retrieve products information - /// - Parameter productIds: The set of product identifiers to retrieve corresponding products for - /// - Parameter completion: handler for result - /// - returns: A cancellable `InAppRequest` object - @discardableResult - public class func retrieveProductsInfo(_ productIds: Set, completion: @escaping (RetrieveResults) -> Void) -> InAppRequest { - return sharedInstance.retrieveProductsInfo(productIds, completion: completion) - } - - /// Purchase a product - /// - Parameter productId: productId as specified in App Store Connect - /// - Parameter quantity: quantity of the product to be purchased - /// - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately) - /// - Parameter applicationUsername: an opaque identifier for the user’s account on your system - /// - Parameter completion: handler for result - /// - returns: A cancellable `InAppRequest` object - @discardableResult - public class func purchaseProduct(_ productId: String, quantity: Int = 1, atomically: Bool = true, applicationUsername: String = "", simulatesAskToBuyInSandbox: Bool = false, completion: @escaping (PurchaseResult) -> Void) -> InAppRequest { - - return sharedInstance.purchaseProduct(productId, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox, completion: completion) - } - - /// Purchase a product - /// - Parameter product: product to be purchased - /// - Parameter quantity: quantity of the product to be purchased - /// - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately) - /// - Parameter applicationUsername: an opaque identifier for the user’s account on your system - /// - Parameter product: optional discount to be applied. Must be of `SKProductPayment` type - /// - Parameter completion: handler for result - public class func purchaseProduct(_ product: SKProduct, quantity: Int = 1, atomically: Bool = true, applicationUsername: String = "", simulatesAskToBuyInSandbox: Bool = false, paymentDiscount: PaymentDiscount? = nil, completion: @escaping ( PurchaseResult) -> Void) { - - sharedInstance.purchase(product: product, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox, paymentDiscount: paymentDiscount, completion: completion) - } - - /// Restore purchases - /// - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately) - /// - Parameter applicationUsername: an opaque identifier for the user’s account on your system - /// - Parameter completion: handler for result - public class func restorePurchases(atomically: Bool = true, applicationUsername: String = "", completion: @escaping (RestoreResults) -> Void) { - - sharedInstance.restorePurchases(atomically: atomically, applicationUsername: applicationUsername, completion: completion) - } - - /// Complete transactions - /// - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately) - /// - Parameter completion: handler for result - public class func completeTransactions(atomically: Bool = true, completion: @escaping ([Purchase]) -> Void) { - - sharedInstance.completeTransactions(atomically: atomically, completion: completion) - } - - /// Finish a transaction - /// - /// Once the content has been delivered, call this method to finish a transaction that was performed non-atomically - /// - Parameter transaction: transaction to finish - public class func finishTransaction(_ transaction: PaymentTransaction) { - - sharedInstance.finishTransaction(transaction) - } - - /// Register a handler for `SKPaymentQueue.shouldAddStorePayment` delegate method. - /// - requires: iOS 11.0+ - public static var shouldAddStorePaymentHandler: ShouldAddStorePaymentHandler? { - didSet { - sharedInstance.paymentQueueController.shouldAddStorePaymentHandler = shouldAddStorePaymentHandler - } - } - - /// Register a handler for `paymentQueue(_:updatedDownloads:)` - /// - seealso: `paymentQueue(_:updatedDownloads:)` - public static var updatedDownloadsHandler: UpdatedDownloadsHandler? { - didSet { - sharedInstance.paymentQueueController.updatedDownloadsHandler = updatedDownloadsHandler - } - } - - public class func start(_ downloads: [SKDownload]) { - sharedInstance.paymentQueueController.start(downloads) - } - public class func pause(_ downloads: [SKDownload]) { - sharedInstance.paymentQueueController.pause(downloads) - } - public class func resume(_ downloads: [SKDownload]) { - sharedInstance.paymentQueueController.resume(downloads) - } - public class func cancel(_ downloads: [SKDownload]) { - sharedInstance.paymentQueueController.cancel(downloads) - } -} - -extension SwiftyStoreKit { - - // MARK: Public methods - Receipt verification - - /// Return receipt data from the application bundle. This is read from `Bundle.main.appStoreReceiptURL`. - public static var localReceiptData: Data? { - return sharedInstance.receiptVerificator.appStoreReceiptData - } - - /// Verify application receipt - /// - Parameter validator: receipt validator to use - /// - Parameter forceRefresh: If `true`, refreshes the receipt even if one already exists. - /// - Parameter completion: handler for result - /// - returns: A cancellable `InAppRequest` object - @discardableResult - public class func verifyReceipt(using validator: ReceiptValidator, forceRefresh: Bool = false, completion: @escaping (VerifyReceiptResult) -> Void) -> InAppRequest? { - - return sharedInstance.receiptVerificator.verifyReceipt(using: validator, forceRefresh: forceRefresh, completion: completion) - } - - /// Fetch application receipt - /// - Parameter forceRefresh: If true, refreshes the receipt even if one already exists. - /// - Parameter completion: handler for result - /// - returns: A cancellable `InAppRequest` object - @discardableResult - public class func fetchReceipt(forceRefresh: Bool, completion: @escaping (FetchReceiptResult) -> Void) -> InAppRequest? { - - return sharedInstance.receiptVerificator.fetchReceipt(forceRefresh: forceRefresh, completion: completion) - } - - /// Verify the purchase of a Consumable or NonConsumable product in a receipt - /// - Parameter productId: the product id of the purchase to verify - /// - Parameter inReceipt: the receipt to use for looking up the purchase - /// - returns: A `VerifyPurchaseResult`, which may be either `notPurchased` or `purchased`. - public class func verifyPurchase(productId: String, inReceipt receipt: ReceiptInfo) -> VerifyPurchaseResult { - - return InAppReceipt.verifyPurchase(productId: productId, inReceipt: receipt) - } - - /** - * Verify the validity of a subscription (auto-renewable, free or non-renewing) in a receipt. - * - * This method extracts all transactions matching the given productId and sorts them by date in descending order. It then compares the first transaction expiry date against the receipt date to determine its validity. - * - Parameter type: `.autoRenewable` or `.nonRenewing`. - * - Parameter productId: The product id of the subscription to verify. - * - Parameter receipt: The receipt to use for looking up the subscription. - * - Parameter validUntil: Date to check against the expiry date of the subscription. This is only used if a date is not found in the receipt. - * - returns: Either `.notPurchased` or `.purchased` / `.expired` with the expiry date found in the receipt. - */ - public class func verifySubscription(ofType type: SubscriptionType, productId: String, inReceipt receipt: ReceiptInfo, validUntil date: Date = Date()) -> VerifySubscriptionResult { - - return InAppReceipt.verifySubscriptions(ofType: type, productIds: [productId], inReceipt: receipt, validUntil: date) - } - - /** - * Verify the validity of a set of subscriptions in a receipt. - * - * This method extracts all transactions matching the given productIds and sorts them by date in descending order. It then compares the first transaction expiry date against the receipt date, to determine its validity. - * - Note: You can use this method to check the validity of (mutually exclusive) subscriptions in a subscription group. - * - Remark: The type parameter determines how the expiration dates are calculated for all subscriptions. Make sure all productIds match the specified subscription type to avoid incorrect results. - * - Parameter type: `.autoRenewable` or `.nonRenewing`. - * - Parameter productIds: The product IDs of the subscriptions to verify. - * - Parameter receipt: The receipt to use for looking up the subscriptions - * - Parameter validUntil: Date to check against the expiry date of the subscriptions. This is only used if a date is not found in the receipt. - * - returns: Either `.notPurchased` or `.purchased` / `.expired` with the expiry date found in the receipt. - */ - public class func verifySubscriptions(ofType type: SubscriptionType = .autoRenewable, productIds: Set, inReceipt receipt: ReceiptInfo, validUntil date: Date = Date()) -> VerifySubscriptionResult { - - return InAppReceipt.verifySubscriptions(ofType: type, productIds: productIds, inReceipt: receipt, validUntil: date) - } - - /// Get the distinct product identifiers from receipt. - /// - /// This Method extracts all product identifiers. (Including cancelled ones). - /// - Note: You can use this method to get all unique product identifiers from receipt. - /// - Parameter type: `.autoRenewable` or `.nonRenewing`. - /// - Parameter receipt: The receipt to use for looking up product identifiers. - /// - returns: Either `Set` or `nil`. - public class func getDistinctPurchaseIds(ofType type: SubscriptionType = .autoRenewable, inReceipt receipt: ReceiptInfo) -> Set? { - - return InAppReceipt.getDistinctPurchaseIds(ofType: type, inReceipt: receipt) - } -} diff --git a/SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift b/Tests/SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift similarity index 100% rename from SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift rename to Tests/SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift diff --git a/SwiftyStoreKitTests/InAppReceiptTests.swift b/Tests/SwiftyStoreKitTests/InAppReceiptTests.swift similarity index 100% rename from SwiftyStoreKitTests/InAppReceiptTests.swift rename to Tests/SwiftyStoreKitTests/InAppReceiptTests.swift diff --git a/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift b/Tests/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift similarity index 100% rename from SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift rename to Tests/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift diff --git a/SwiftyStoreKitTests/Info.plist b/Tests/SwiftyStoreKitTests/Info.plist similarity index 100% rename from SwiftyStoreKitTests/Info.plist rename to Tests/SwiftyStoreKitTests/Info.plist diff --git a/SwiftyStoreKitTests/PaymentQueueControllerTests.swift b/Tests/SwiftyStoreKitTests/PaymentQueueControllerTests.swift similarity index 100% rename from SwiftyStoreKitTests/PaymentQueueControllerTests.swift rename to Tests/SwiftyStoreKitTests/PaymentQueueControllerTests.swift diff --git a/SwiftyStoreKitTests/PaymentQueueSpy.swift b/Tests/SwiftyStoreKitTests/PaymentQueueSpy.swift similarity index 100% rename from SwiftyStoreKitTests/PaymentQueueSpy.swift rename to Tests/SwiftyStoreKitTests/PaymentQueueSpy.swift diff --git a/SwiftyStoreKitTests/PaymentTransactionObserverFake.swift b/Tests/SwiftyStoreKitTests/PaymentTransactionObserverFake.swift similarity index 100% rename from SwiftyStoreKitTests/PaymentTransactionObserverFake.swift rename to Tests/SwiftyStoreKitTests/PaymentTransactionObserverFake.swift diff --git a/SwiftyStoreKitTests/PaymentsControllerTests.swift b/Tests/SwiftyStoreKitTests/PaymentsControllerTests.swift similarity index 100% rename from SwiftyStoreKitTests/PaymentsControllerTests.swift rename to Tests/SwiftyStoreKitTests/PaymentsControllerTests.swift diff --git a/SwiftyStoreKitTests/ProductsInfoControllerTests.swift b/Tests/SwiftyStoreKitTests/ProductsInfoControllerTests.swift similarity index 100% rename from SwiftyStoreKitTests/ProductsInfoControllerTests.swift rename to Tests/SwiftyStoreKitTests/ProductsInfoControllerTests.swift diff --git a/SwiftyStoreKitTests/RestorePurchasesControllerTests.swift b/Tests/SwiftyStoreKitTests/RestorePurchasesControllerTests.swift similarity index 100% rename from SwiftyStoreKitTests/RestorePurchasesControllerTests.swift rename to Tests/SwiftyStoreKitTests/RestorePurchasesControllerTests.swift diff --git a/SwiftyStoreKitTests/TestPaymentTransaction.swift b/Tests/SwiftyStoreKitTests/TestPaymentTransaction.swift similarity index 100% rename from SwiftyStoreKitTests/TestPaymentTransaction.swift rename to Tests/SwiftyStoreKitTests/TestPaymentTransaction.swift diff --git a/SwiftyStoreKitTests/TestProduct.swift b/Tests/SwiftyStoreKitTests/TestProduct.swift similarity index 100% rename from SwiftyStoreKitTests/TestProduct.swift rename to Tests/SwiftyStoreKitTests/TestProduct.swift From d3bee96cd24720692e6dcd15f12002868524fb18 Mon Sep 17 00:00:00 2001 From: Stefanos Zachariadis Date: Sat, 18 Jul 2020 10:47:16 +0100 Subject: [PATCH 9/9] set minimum target versions. Otherwise cannot deploy using swiftpm to watchos --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 2cc94edf..711c9408 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,9 @@ -// swift-tools-version:4.2 +// swift-tools-version:5.2 import PackageDescription let package = Package( name: "SwiftyStoreKit", - // platforms: [.iOS("8.0"), .macOS("10.10"), tvOS("9.0"), .watchOS("2.0")], + platforms: [.iOS("8.0"), .macOS("10.10"), .tvOS("9.0"), .watchOS("6.2")], products: [ .library(name: "SwiftyStoreKit", targets: ["SwiftyStoreKit"]) ],