From 8f77cd51d27d8ad5fd603ab5d8a5250ecf73b8cb Mon Sep 17 00:00:00 2001 From: Andrea Bizzotto Date: Thu, 19 May 2016 23:23:38 +0100 Subject: [PATCH 1/7] Dispatch verifyReceipt callback on main thread --- SwiftyStoreKit/SwiftyStoreKit.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/SwiftyStoreKit/SwiftyStoreKit.swift b/SwiftyStoreKit/SwiftyStoreKit.swift index 40d12a92..ea08c4ab 100644 --- a/SwiftyStoreKit/SwiftyStoreKit.swift +++ b/SwiftyStoreKit/SwiftyStoreKit.swift @@ -158,7 +158,12 @@ public class SwiftyStoreKit { password: String? = nil, session: NSURLSession = NSURLSession.sharedSession(), completion:(result: VerifyReceiptResult) -> ()) { - InAppReceipt.verify(receiptVerifyURL: url, password: password, session: session, completion: completion) + InAppReceipt.verify(receiptVerifyURL: url, password: password, session: session) { result in + + dispatch_async(dispatch_get_main_queue()) { + completion(result: result) + } + } } /** From 2505d676ae36223bc5f00e96d0a490bd90f02b88 Mon Sep 17 00:00:00 2001 From: Andrea Bizzotto Date: Thu, 19 May 2016 23:24:31 +0100 Subject: [PATCH 2/7] Updated names on verifyPurchase implementation --- SwiftyStoreKit/InAppReceipt.swift | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/SwiftyStoreKit/InAppReceipt.swift b/SwiftyStoreKit/InAppReceipt.swift index 25437ba7..31af4cc4 100644 --- a/SwiftyStoreKit/InAppReceipt.swift +++ b/SwiftyStoreKit/InAppReceipt.swift @@ -254,21 +254,20 @@ internal class InAppReceipt { validUntil: NSDate? = nil ) -> SwiftyStoreKit.VerifyPurchaseResult { - // Force type of the latest_receipt_info - guard let inAppPurchases = receipt["receipt"]?["in_app"] as? [ReceiptInfo] - else { + // Get all receipts + guard let allReceipts = receipt["receipt"]?["in_app"] as? [ReceiptInfo] else { return .NotPurchased } - // Filter receipt with right product id - let receiptsWithGoodProductId = inAppPurchases + // Filter receipts with matching product id + let receiptsMatchingProductId = allReceipts .filter { (receipt) -> Bool in - let product_id = receipt["product_id"] as? String - return product_id == productId + let product_id = receipt["product_id"] as? String + return product_id == productId } // Verify that at least one receipt has the right product id - guard receiptsWithGoodProductId.count >= 1 else { + guard receiptsMatchingProductId.count >= 1 else { return .NotPurchased } @@ -278,8 +277,10 @@ internal class InAppReceipt { } // Return the expires dates sorted desc - let expiresDates = receiptsWithGoodProductId + let expiresDates = receiptsMatchingProductId .map { (receipt) -> NSDate in + // TODO: should use 'expires_date' or 'expiration_date' instead? See: + // https://developer.apple.com/library/mac/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html let expires_date = receipt["expires_date_ms"] as? NSString let expires_date_double = (expires_date?.doubleValue ?? 0.0) / 1000 return NSDate(timeIntervalSince1970: expires_date_double) @@ -295,14 +296,14 @@ internal class InAppReceipt { } // Check if at least 1 receipt is valid - if validExpiresDate.count >= 1 { + if let firstValidExpiresDate = validExpiresDate.first { // The subscription is valid - return .Purchased(expiresDate: validExpiresDate.first!) + return .Purchased(expiresDate: firstValidExpiresDate) } else { // The subscription is expired return .Expired(expiresDate: expiresDates.first!) } } - + } From 9d15648d88975429df8d7ece9a08cde10afb5215 Mon Sep 17 00:00:00 2001 From: Andrea Bizzotto Date: Thu, 19 May 2016 23:25:09 +0100 Subject: [PATCH 3/7] Updated view controllers and storyboards with verifyPurchase actions and alerts --- SwiftyStoreDemo/Base.lproj/Main.storyboard | 44 ++++++++------ SwiftyStoreDemo/ViewController.swift | 53 ++++++++++++++--- SwiftyStoreOSXDemo/Base.lproj/Main.storyboard | 46 +++++++++------ SwiftyStoreOSXDemo/ViewController.swift | 57 +++++++++++++++---- 4 files changed, 148 insertions(+), 52 deletions(-) diff --git a/SwiftyStoreDemo/Base.lproj/Main.storyboard b/SwiftyStoreDemo/Base.lproj/Main.storyboard index c6572a8e..b0d767e7 100644 --- a/SwiftyStoreDemo/Base.lproj/Main.storyboard +++ b/SwiftyStoreDemo/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -22,22 +22,7 @@ - - - - - - - + - + + - + - + + + + + + @@ -100,20 +115,22 @@ + + - + + - + + - - - + + - + - + - - - - - - - - - - + @@ -172,7 +190,7 @@ - - @@ -225,7 +232,6 @@ - diff --git a/SwiftyStoreDemo/ViewController.swift b/SwiftyStoreDemo/ViewController.swift index 75485c6b..dd774243 100644 --- a/SwiftyStoreDemo/ViewController.swift +++ b/SwiftyStoreDemo/ViewController.swift @@ -26,28 +26,47 @@ import UIKit import StoreKit import SwiftyStoreKit +enum RegisteredPurchase : String { + + case Purchase1 = "purchase1" + case Purchase2 = "purchase2" + case NonConsumablePurchase = "nonConsumablePurchase" + case ConsumablePurchase = "consumablePurchase" + case AutoRenewablePurchase = "autoRenewablePurchase" +} + + class ViewController: UIViewController { let AppBundleId = "com.musevisions.iOS.SwiftyStoreKit" + let Purchase1 = RegisteredPurchase.Purchase1.rawValue + let Purchase2 = RegisteredPurchase.AutoRenewablePurchase.rawValue + // MARK: actions @IBAction func getInfo1() { - getInfo("purchase1") - } - @IBAction func getInfo2() { - getInfo("consumablePurchase") + getInfo(Purchase1) } @IBAction func purchase1() { - purchase("purchase1") + purchase(Purchase1) + } + @IBAction func verifyPurchase1() { + verifyPurchase(Purchase1) + } + @IBAction func getInfo2() { + getInfo(Purchase2) } @IBAction func purchase2() { - purchase("consumablePurchase") + purchase(Purchase2) } - - func getInfo(no: String) { + @IBAction func verifyPurchase2() { + verifyPurchase(Purchase2) + } + + func getInfo(purchaseName: String) { NetworkActivityIndicatorManager.networkOperationStarted() - SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + no]) { result in + SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchaseName]) { result in NetworkActivityIndicatorManager.networkOperationFinished() self.showAlert(self.alertForProductRetrievalInfo(result)) @@ -88,8 +107,8 @@ class ViewController: UIViewController { } } } - - @IBAction func verifyPurchase() { + + func verifyPurchase(purchaseName: String) { NetworkActivityIndicatorManager.networkOperationStarted() SwiftyStoreKit.verifyReceipt() { result in @@ -99,9 +118,9 @@ class ViewController: UIViewController { case .Success(let receipt): let purchaseResult = SwiftyStoreKit.verifyPurchase( - productId: self.AppBundleId + "consumablePurchase", + productId: self.AppBundleId + "." + purchaseName, inReceipt: receipt, - validUntil: NSDate() + validUntil: nil ) self.showAlert(self.alertForVerifyPurchase(purchaseResult)) diff --git a/SwiftyStoreOSXDemo/Base.lproj/Main.storyboard b/SwiftyStoreOSXDemo/Base.lproj/Main.storyboard index 0a1db8e0..21e2bdca 100644 --- a/SwiftyStoreOSXDemo/Base.lproj/Main.storyboard +++ b/SwiftyStoreOSXDemo/Base.lproj/Main.storyboard @@ -720,11 +720,23 @@ + + + @@ -762,13 +774,25 @@ + + + @@ -804,19 +828,8 @@ - - @@ -824,10 +837,9 @@ - + - diff --git a/SwiftyStoreOSXDemo/ViewController.swift b/SwiftyStoreOSXDemo/ViewController.swift index 1411edf6..19a8081a 100644 --- a/SwiftyStoreOSXDemo/ViewController.swift +++ b/SwiftyStoreOSXDemo/ViewController.swift @@ -26,35 +26,54 @@ import Cocoa import StoreKit import SwiftyStoreKit +enum RegisteredPurchase : String { + + case Purchase1 = "purchase1" + case Purchase2 = "purchase2" + case NonConsumablePurchase = "nonConsumablePurchase" + case ConsumablePurchase = "consumablePurchase" + case AutoRenewablePurchase = "autoRenewablePurchase" +} + class ViewController: NSViewController { let AppBundleId = "com.musevisions.OSX.SwiftyStoreKit" + let Purchase1 = RegisteredPurchase.Purchase1.rawValue + let Purchase2 = RegisteredPurchase.AutoRenewablePurchase.rawValue + // MARK: actions @IBAction func getInfo1(sender: AnyObject?) { - getInfo("purchase1") - } - @IBAction func getInfo2(sender: AnyObject?) { - getInfo("consumablePurchase") + getInfo(Purchase1) } @IBAction func purchase1(sender: AnyObject?) { - purchase("purchase1") + purchase(Purchase1) + } + @IBAction func verifyPurchase1(sender: AnyObject?) { + verifyPurchase(Purchase1) + } + + @IBAction func getInfo2(sender: AnyObject?) { + getInfo(Purchase2) } @IBAction func purchase2(sender: AnyObject?) { - purchase("consumablePurchase") + purchase(Purchase2) + } + @IBAction func verifyPurchase2(sender: AnyObject?) { + verifyPurchase(Purchase2) } - func getInfo(no: String) { + func getInfo(purchaseName: String) { - SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + no]) { result in + SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchaseName]) { result in self.showAlert(self.alertForProductRetrievalInfo(result)) } } - func purchase(no: String) { + func purchase(purchaseName: String) { - SwiftyStoreKit.purchaseProduct(AppBundleId + "." + no) { result in + SwiftyStoreKit.purchaseProduct(AppBundleId + "." + purchaseName) { result in self.showAlert(self.alertForPurchaseResult(result)) } @@ -79,7 +98,7 @@ class ViewController: NSViewController { } } - @IBAction func verifyPurchase(sender: AnyObject?) { + func verifyPurchase(purchaseName: String) { SwiftyStoreKit.verifyReceipt() { result in @@ -87,9 +106,9 @@ class ViewController: NSViewController { case .Success(let receipt): let purchaseResult = SwiftyStoreKit.verifyPurchase( - productId: self.AppBundleId + "consumablePurchase", + productId: self.AppBundleId + "." + purchaseName, inReceipt: receipt, - validUntil: NSDate() + validUntil: nil ) self.showAlert(self.alertForVerifyPurchase(purchaseResult)) From c3b0f300e5d7ca1c43f2024d5ad123014e4e8b5d Mon Sep 17 00:00:00 2001 From: Andrea Bizzotto Date: Sun, 22 May 2016 18:05:19 +0100 Subject: [PATCH 5/7] Added PurchaseType enum to be used by verifyPurchase() method. AutomaticallyRenewableSubscription and NonRenewingSubscription types now provide a validUntilDate property that is checked against the receipts expiration dates to determine if the subscription is purchased or expired --- SwiftyStoreDemo/ViewController.swift | 32 +++++-- SwiftyStoreKit/InAppReceipt.swift | 114 ++++++++++++++---------- SwiftyStoreKit/SwiftyStoreKit.swift | 4 +- SwiftyStoreOSXDemo/ViewController.swift | 28 ++++-- 4 files changed, 110 insertions(+), 68 deletions(-) diff --git a/SwiftyStoreDemo/ViewController.swift b/SwiftyStoreDemo/ViewController.swift index dd774243..2f9938ad 100644 --- a/SwiftyStoreDemo/ViewController.swift +++ b/SwiftyStoreDemo/ViewController.swift @@ -33,6 +33,16 @@ enum RegisteredPurchase : String { case NonConsumablePurchase = "nonConsumablePurchase" case ConsumablePurchase = "consumablePurchase" case AutoRenewablePurchase = "autoRenewablePurchase" + + var purchaseType: SwiftyStoreKit.PurchaseType { + switch self { + case .Purchase1: return .NonConsumable + case .Purchase2: return .NonConsumable + case .NonConsumablePurchase: return .NonConsumable + case .ConsumablePurchase: return .Consumable + case .AutoRenewablePurchase: return .AutomaticallyRenewableSubscription(validUntilDate: NSDate()) + } + } } @@ -40,8 +50,8 @@ class ViewController: UIViewController { let AppBundleId = "com.musevisions.iOS.SwiftyStoreKit" - let Purchase1 = RegisteredPurchase.Purchase1.rawValue - let Purchase2 = RegisteredPurchase.AutoRenewablePurchase.rawValue + let Purchase1 = RegisteredPurchase.Purchase1 + let Purchase2 = RegisteredPurchase.AutoRenewablePurchase // MARK: actions @IBAction func getInfo1() { @@ -63,20 +73,20 @@ class ViewController: UIViewController { verifyPurchase(Purchase2) } - func getInfo(purchaseName: String) { + func getInfo(purchase: RegisteredPurchase) { NetworkActivityIndicatorManager.networkOperationStarted() - SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchaseName]) { result in + SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchase.rawValue]) { result in NetworkActivityIndicatorManager.networkOperationFinished() self.showAlert(self.alertForProductRetrievalInfo(result)) } } - func purchase(no: String) { + func purchase(purchase: RegisteredPurchase) { NetworkActivityIndicatorManager.networkOperationStarted() - SwiftyStoreKit.purchaseProduct(AppBundleId + "." + no) { result in + SwiftyStoreKit.purchaseProduct(AppBundleId + "." + purchase.rawValue) { result in NetworkActivityIndicatorManager.networkOperationFinished() self.showAlert(self.alertForPurchaseResult(result)) @@ -108,7 +118,7 @@ class ViewController: UIViewController { } } - func verifyPurchase(purchaseName: String) { + func verifyPurchase(purchase: RegisteredPurchase) { NetworkActivityIndicatorManager.networkOperationStarted() SwiftyStoreKit.verifyReceipt() { result in @@ -118,9 +128,9 @@ class ViewController: UIViewController { case .Success(let receipt): let purchaseResult = SwiftyStoreKit.verifyPurchase( - productId: self.AppBundleId + "." + purchaseName, + productId: self.AppBundleId + "." + purchase.rawValue, inReceipt: receipt, - validUntil: nil + purchaseType: purchase.purchaseType ) self.showAlert(self.alertForVerifyPurchase(purchaseResult)) @@ -240,12 +250,16 @@ extension ViewController { switch result { case .Purchased(let expiresDate): if let expiresDate = expiresDate { + print("Product is valid until \(expiresDate)") return alertWithTitle("Product is purchased", message: "Product is valid until \(expiresDate)") } + print("Product is purchased") return alertWithTitle("Product is purchased", message: "Product will not expire") case .Expired(let expiresDate): // Only for Automatically Renewable Subscription + print("Product is expired since \(expiresDate)") return alertWithTitle("Product expired", message: "Product is expired since \(expiresDate)") case .NotPurchased: + print("This product has never been purchased") return alertWithTitle("Not purchased", message: "This product has never been purchased") } } diff --git a/SwiftyStoreKit/InAppReceipt.swift b/SwiftyStoreKit/InAppReceipt.swift index 31af4cc4..97e9aa62 100644 --- a/SwiftyStoreKit/InAppReceipt.swift +++ b/SwiftyStoreKit/InAppReceipt.swift @@ -30,6 +30,18 @@ public typealias ReceiptInfo = [String: AnyObject] // MARK: - Enumeration extension SwiftyStoreKit { + public enum PurchaseType { + // A consumable In-App Purchase must be purchased every time the user downloads it. + case Consumable + // Non-consumable In-App Purchases only need to be purchased once by users. + case NonConsumable + // Automatically renewable subscriptions allow the user to purchase updating and dynamic content for a set duration of time. + case AutomaticallyRenewableSubscription(validUntilDate: NSDate) + // Free subscriptions don’t expire and can only be offered in apps that are in the Magazines & Newspapers category. + case FreeSubscription + // Non-Renewing Subscriptions allow the sale of services with a limited duration. + case NonRenewingSubscription(validUntilDate: NSDate) + } public enum VerifyReceiptResult { case Success(receipt: ReceiptInfo) case Error(error: ReceiptError) @@ -251,59 +263,65 @@ internal class InAppReceipt { class func verifyPurchase( productId productId: String, inReceipt receipt: ReceiptInfo, - validUntil: NSDate? = nil + purchaseType: SwiftyStoreKit.PurchaseType ) -> SwiftyStoreKit.VerifyPurchaseResult { - // Get all receipts - guard let allReceipts = receipt["receipt"]?["in_app"] as? [ReceiptInfo] else { - return .NotPurchased - } + // Get all receipts + guard let allReceipts = receipt["receipt"]?["in_app"] as? [ReceiptInfo] else { + return .NotPurchased + } - // Filter receipts with matching product id - let receiptsMatchingProductId = allReceipts - .filter { (receipt) -> Bool in + // Filter receipts with matching product id + let receiptsMatchingProductId = allReceipts + .filter { (receipt) -> Bool in let product_id = receipt["product_id"] as? String return product_id == productId - } - - // Verify that at least one receipt has the right product id - guard receiptsMatchingProductId.count >= 1 else { - return .NotPurchased - } - - guard let validUntil = validUntil else { - // Do not need to verify the expiration date - return .Purchased(expiresDate: nil) - } - - // Return the expires dates sorted desc - let expiresDates = receiptsMatchingProductId - .map { (receipt) -> NSDate in - // TODO: should use 'expires_date' or 'expiration_date' instead? See: - // https://developer.apple.com/library/mac/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html - let expires_date = receipt["expires_date_ms"] as? NSString - let expires_date_double = (expires_date?.doubleValue ?? 0.0) / 1000 - return NSDate(timeIntervalSince1970: expires_date_double) - } - .sort { (a, b) -> Bool in - return a.compare(b) == .OrderedDescending - } + } - // Filter expired date - let validExpiresDate = expiresDates - .filter { (expires_date) -> Bool in - return expires_date.compare(validUntil) == .OrderedDescending - } + // Verify that at least one receipt has the right product id + guard receiptsMatchingProductId.count >= 1 else { + return .NotPurchased + } - // Check if at least 1 receipt is valid - if let firstValidExpiresDate = validExpiresDate.first { - // The subscription is valid - return .Purchased(expiresDate: firstValidExpiresDate) - } - else { - // The subscription is expired - return .Expired(expiresDate: expiresDates.first!) - } - } - + switch purchaseType { + // Do not need to verify the expiration date + case .Consumable, .NonConsumable, .FreeSubscription: + return .Purchased(expiresDate: nil) + case .AutomaticallyRenewableSubscription(let validUntilDate): + return verifyPurchase(receiptsMatchingProductId, validUntilDate: validUntilDate) + case .NonRenewingSubscription(let validUntilDate): + return verifyPurchase(receiptsMatchingProductId, validUntilDate: validUntilDate) + } + } + + private class func verifyPurchase(receiptsMatchingProductId: [ReceiptInfo], validUntilDate date: NSDate) -> SwiftyStoreKit.VerifyPurchaseResult { + // Return the expires dates sorted desc + let expiresDates = receiptsMatchingProductId + .map { (receipt) -> NSDate in + // TODO: should use 'expires_date' or 'expiration_date' instead? See: + // https://developer.apple.com/library/mac/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html + let expires_date = receipt["expires_date_ms"] as? NSString + let expires_date_double = (expires_date?.doubleValue ?? 0.0) / 1000 + return NSDate(timeIntervalSince1970: expires_date_double) + } + .sort { (a, b) -> Bool in + return a.compare(b) == .OrderedDescending + } + + // Filter expired date + let validExpiresDate = expiresDates + .filter { (expires_date) -> Bool in + return expires_date.compare(date) == .OrderedDescending + } + + // Check if at least 1 receipt is valid + if let firstValidExpiresDate = validExpiresDate.first { + // The subscription is valid + return .Purchased(expiresDate: firstValidExpiresDate) + } + else { + // The subscription is expired + return .Expired(expiresDate: expiresDates.first!) + } + } } diff --git a/SwiftyStoreKit/SwiftyStoreKit.swift b/SwiftyStoreKit/SwiftyStoreKit.swift index ea08c4ab..c7108b92 100644 --- a/SwiftyStoreKit/SwiftyStoreKit.swift +++ b/SwiftyStoreKit/SwiftyStoreKit.swift @@ -175,9 +175,9 @@ public class SwiftyStoreKit { public class func verifyPurchase( productId productId: String, inReceipt receipt: ReceiptInfo, - validUntil: NSDate? = nil + purchaseType: PurchaseType ) -> SwiftyStoreKit.VerifyPurchaseResult { - return InAppReceipt.verifyPurchase(productId: productId, inReceipt: receipt, validUntil: validUntil) + return InAppReceipt.verifyPurchase(productId: productId, inReceipt: receipt, purchaseType: purchaseType) } #if os(iOS) || os(tvOS) diff --git a/SwiftyStoreOSXDemo/ViewController.swift b/SwiftyStoreOSXDemo/ViewController.swift index 19a8081a..51669f8c 100644 --- a/SwiftyStoreOSXDemo/ViewController.swift +++ b/SwiftyStoreOSXDemo/ViewController.swift @@ -33,14 +33,24 @@ enum RegisteredPurchase : String { case NonConsumablePurchase = "nonConsumablePurchase" case ConsumablePurchase = "consumablePurchase" case AutoRenewablePurchase = "autoRenewablePurchase" + + var purchaseType: SwiftyStoreKit.PurchaseType { + switch self { + case .Purchase1: return .NonConsumable + case .Purchase2: return .NonConsumable + case .NonConsumablePurchase: return .NonConsumable + case .ConsumablePurchase: return .Consumable + case .AutoRenewablePurchase: return .AutomaticallyRenewableSubscription(validUntilDate: NSDate()) + } + } } class ViewController: NSViewController { let AppBundleId = "com.musevisions.OSX.SwiftyStoreKit" - let Purchase1 = RegisteredPurchase.Purchase1.rawValue - let Purchase2 = RegisteredPurchase.AutoRenewablePurchase.rawValue + let Purchase1 = RegisteredPurchase.Purchase1 + let Purchase2 = RegisteredPurchase.AutoRenewablePurchase // MARK: actions @IBAction func getInfo1(sender: AnyObject?) { @@ -63,17 +73,17 @@ class ViewController: NSViewController { verifyPurchase(Purchase2) } - func getInfo(purchaseName: String) { + func getInfo(purchase: RegisteredPurchase) { - SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchaseName]) { result in + SwiftyStoreKit.retrieveProductsInfo([AppBundleId + "." + purchase.rawValue]) { result in self.showAlert(self.alertForProductRetrievalInfo(result)) } } - func purchase(purchaseName: String) { + func purchase(purchase: RegisteredPurchase) { - SwiftyStoreKit.purchaseProduct(AppBundleId + "." + purchaseName) { result in + SwiftyStoreKit.purchaseProduct(AppBundleId + "." + purchase.rawValue) { result in self.showAlert(self.alertForPurchaseResult(result)) } @@ -98,7 +108,7 @@ class ViewController: NSViewController { } } - func verifyPurchase(purchaseName: String) { + func verifyPurchase(purchase: RegisteredPurchase) { SwiftyStoreKit.verifyReceipt() { result in @@ -106,9 +116,9 @@ class ViewController: NSViewController { case .Success(let receipt): let purchaseResult = SwiftyStoreKit.verifyPurchase( - productId: self.AppBundleId + "." + purchaseName, + productId: self.AppBundleId + "." + purchase.rawValue, inReceipt: receipt, - validUntil: nil + purchaseType: purchase.purchaseType ) self.showAlert(self.alertForVerifyPurchase(purchaseResult)) From 4e6477d42182e4cf8b64a7093c2d480e4a4b370b Mon Sep 17 00:00:00 2001 From: Andrea Bizzotto Date: Sun, 22 May 2016 18:16:12 +0100 Subject: [PATCH 6/7] Updated README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5f5c05e..6f4cd72e 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,8 @@ SwiftyStoreKit.verifyReceipt() { result in let purchaseResult = SwiftyStoreKit.verifyPurchase( productId: "com.musevisions.SwiftyStoreKit.Purchase1", - inReceipt: receipt + inReceipt: receipt, + purchaseType: .NonConsumable ) switch purchaseResult { case .Purchased(let expiresDate): From d25d3ef971d39430c76aca9b488d3e799e60f75b Mon Sep 17 00:00:00 2001 From: Andrea Bizzotto Date: Sun, 22 May 2016 18:25:06 +0100 Subject: [PATCH 7/7] Removed TODO --- SwiftyStoreKit/InAppReceipt.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/SwiftyStoreKit/InAppReceipt.swift b/SwiftyStoreKit/InAppReceipt.swift index 97e9aa62..6f52d162 100644 --- a/SwiftyStoreKit/InAppReceipt.swift +++ b/SwiftyStoreKit/InAppReceipt.swift @@ -298,8 +298,6 @@ internal class InAppReceipt { // Return the expires dates sorted desc let expiresDates = receiptsMatchingProductId .map { (receipt) -> NSDate in - // TODO: should use 'expires_date' or 'expiration_date' instead? See: - // https://developer.apple.com/library/mac/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html let expires_date = receipt["expires_date_ms"] as? NSString let expires_date_double = (expires_date?.doubleValue ?? 0.0) / 1000 return NSDate(timeIntervalSince1970: expires_date_double)