瀏覽代碼

Move receipt refresh and verification code to InAppReceiptVerificator.
Removed refreshReceipt method from SwiftyStoreKit.swift as this is now performed internally

Andrea Bizzotto 8 年之前
父節點
當前提交
60b06c0ba8

+ 11 - 19
README.md

@@ -214,31 +214,23 @@ let receiptString = receiptData.base64EncodedString(options: [])
 
 ```swift
 let appleValidator = AppleReceiptValidator(service: .production)
-SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
-    if case .error(let error) = result {
-        if case .noReceiptData = error {
-            self.refreshReceipt()
-        }
-    }
-}
-
-func refreshReceipt() {
-    SwiftyStoreKit.refreshReceipt { result in
-        switch result {
-        case .success(let receiptData):
-            print("Receipt refresh success: \(receiptData.base64EncodedString)")
-        case .error(let error):
-            print("Receipt refresh failed: \(error)")
-        }
-    }
+let password = "your-shared-secret"
+SwiftyStoreKit.verifyReceipt(using: appleValidator, password: password) { result in
+    switch result {
+    case .success(let receipt):
+        print("Verify receipt Success: \(receipt)")
+    case .error(let error):
+        print("Verify receipt Failed: \(error)")
+	}
 }
 ```
 
 #### Notes
 
-* If the user is not logged to iTunes when `refreshReceipt` is called, StoreKit will present a popup asking to **Sign In to the iTunes Store**.
-* If the user enters valid credentials, the receipt will be refreshed.
+* If the user is not logged to iTunes when `verifyReceipt` is called, StoreKit will present a popup asking to **Sign In to the iTunes Store**.
+* If the user enters valid credentials, the receipt will be refreshed and verified.
 * If the user cancels, receipt refresh will fail with a **Cannot connect to iTunes Store** error.
+* The receipt is only refreshed if it's not already stored in `Bundle.main.appStoreReceiptURL`.
 
 
 ### Verify Purchase

+ 16 - 39
SwiftyStoreKit-iOS-Demo/ViewController.swift

@@ -62,7 +62,7 @@ class ViewController: UIViewController {
     @IBAction func verifyPurchase2() {
         verifyPurchase(purchase2Suffix)
     }
-
+    
     func getInfo(_ purchase: RegisteredPurchase) {
 
         NetworkActivityIndicatorManager.networkOperationStarted()
@@ -108,25 +108,23 @@ class ViewController: UIViewController {
     @IBAction func verifyReceipt() {
 
         NetworkActivityIndicatorManager.networkOperationStarted()
-		let appleValidator = AppleReceiptValidator(service: .production)
-		SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
+        verifyReceipt { result in
             NetworkActivityIndicatorManager.networkOperationFinished()
-
             self.showAlert(self.alertForVerifyReceipt(result))
-
-            if case .error(let error) = result {
-                if case .noReceiptData = error {
-                    self.refreshReceipt()
-                }
-            }
         }
     }
+    
+    func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {
+        
+        let appleValidator = AppleReceiptValidator(service: .production)
+        let password = "your-shared-secret"
+        SwiftyStoreKit.verifyReceipt(using: appleValidator, password: password, completion: completion)
+    }
 
     func verifyPurchase(_ purchase: RegisteredPurchase) {
 
         NetworkActivityIndicatorManager.networkOperationStarted()
-		let appleValidator = AppleReceiptValidator(service: .production)
-		SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
+        verifyReceipt { result in
             NetworkActivityIndicatorManager.networkOperationFinished()
 
             switch result {
@@ -159,23 +157,12 @@ class ViewController: UIViewController {
                     self.showAlert(self.alertForVerifyPurchase(purchaseResult))
                 }
 
-            case .error(let error):
+            case .error:
                 self.showAlert(self.alertForVerifyReceipt(result))
-                if case .noReceiptData = error {
-                    self.refreshReceipt()
-                }
             }
         }
     }
 
-    func refreshReceipt() {
-
-        SwiftyStoreKit.refreshReceipt { result in
-
-            self.showAlert(self.alertForRefreshReceipt(result))
-        }
-    }
-
 #if os(iOS)
     override var preferredStatusBarStyle: UIStatusBarStyle {
         return .lightContent
@@ -262,14 +249,16 @@ extension ViewController {
         switch result {
         case .success(let receipt):
             print("Verify receipt Success: \(receipt)")
-            return alertWithTitle("Receipt verified", message: "Receipt verified remotly")
+            return alertWithTitle("Receipt verified", message: "Receipt verified remotely")
         case .error(let error):
             print("Verify receipt Failed: \(error)")
             switch error {
-            case .noReceiptData :
+            case .noReceiptData:
                 return alertWithTitle("Receipt verification", message: "No receipt data, application will try to get a new one. Try again.")
+            case .networkError(let error):
+                return alertWithTitle("Receipt verification", message: "Network error while verifying receipt: \(error)")
             default:
-                return alertWithTitle("Receipt verification", message: "Receipt verification failed")
+                return alertWithTitle("Receipt verification", message: "Receipt verification failed: \(error)")
             }
         }
     }
@@ -300,16 +289,4 @@ extension ViewController {
             return alertWithTitle("Not purchased", message: "This product has never been purchased")
         }
     }
-
-    func alertForRefreshReceipt(_ result: RefreshReceiptResult) -> UIAlertController {
-        switch result {
-        case .success(let receiptData):
-            print("Receipt refresh Success: \(receiptData.base64EncodedString)")
-            return alertWithTitle("Receipt refreshed", message: "Receipt refreshed successfully")
-        case .error(let error):
-            print("Receipt refresh Failed: \(error)")
-            return alertWithTitle("Receipt refresh failed", message: "Receipt refresh failed")
-        }
-    }
-
 }

+ 19 - 35
SwiftyStoreKit-macOS-Demo/ViewController.swift

@@ -105,24 +105,22 @@ class ViewController: NSViewController {
 
     @IBAction func verifyReceipt(_ sender: Any?) {
 
-        let appleValidator = AppleReceiptValidator(service: .production)
-        SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
-
-            self.showAlert(self.alertForVerifyReceipt(result)) { _ in
-
-                if case .error(let error) = result {
-                    if case .noReceiptData = error {
-                        self.refreshReceipt()
-                    }
-                }
-            }
+        verifyReceipt { result in
+            self.showAlert(self.alertForVerifyReceipt(result))
         }
     }
+    
+    func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {
+        
+        let appleValidator = AppleReceiptValidator(service: .production)
+        let password = "your-shared-secret"
+        SwiftyStoreKit.verifyReceipt(using: appleValidator, password: password, completion: completion)
+    }
 
     func verifyPurchase(_ purchase: RegisteredPurchase) {
 
         let appleValidator = AppleReceiptValidator(service: .production)
-        SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
+        verifyReceipt { result in
 
             switch result {
             case .success(let receipt):
@@ -157,15 +155,6 @@ class ViewController: NSViewController {
             }
         }
     }
-
-    func refreshReceipt() {
-
-        SwiftyStoreKit.refreshReceipt { result in
-
-            self.showAlert(self.alertForRefreshReceipt(result))
-        }
-    }
-
 }
 
 // MARK: User facing alerts
@@ -244,10 +233,17 @@ extension ViewController {
         switch result {
         case .success(let receipt):
             print("Verify receipt Success: \(receipt)")
-            return self.alertWithTitle("Receipt verified", message: "Receipt verified remotly")
+            return self.alertWithTitle("Receipt verified", message: "Receipt verified remotely")
         case .error(let error):
             print("Verify receipt Failed: \(error)")
-            return self.alertWithTitle("Receipt verification failed", message: "The application will exit to create receipt data. You must have signed the application with your developer id to test and be outside of XCode")
+            switch error {
+            case .noReceiptData:
+                return alertWithTitle("Receipt verification", message: "No receipt data, application will try to get a new one. Try again.")
+            case .networkError(let error):
+                return alertWithTitle("Receipt verification", message: "Network error while verifying receipt: \(error)")
+            default:
+                return alertWithTitle("Receipt verification", message: "Receipt verification failed: \(error)")
+            }
         }
     }
 
@@ -277,16 +273,4 @@ extension ViewController {
             return alertWithTitle("Not purchased", message: "This product has never been purchased")
         }
     }
-
-    func alertForRefreshReceipt(_ result: RefreshReceiptResult) -> NSAlert {
-        switch result {
-        case .success(let receiptData):
-            print("Receipt refresh Success: \(receiptData.base64EncodedString)")
-            return alertWithTitle("Receipt refreshed", message: "Receipt refreshed successfully")
-        case .error(let error):
-            print("Receipt refresh Failed: \(error)")
-            return alertWithTitle("Receipt refresh failed", message: "Receipt refresh failed")
-        }
-    }
-
 }

+ 11 - 2
SwiftyStoreKit.xcodeproj/project.pbxproj

@@ -47,6 +47,9 @@
 		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 */; };
+		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 */; };
@@ -179,6 +182,7 @@
 		658A084B1E2EC5960074A98F /* PaymentQueueSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentQueueSpy.swift; sourceTree = "<group>"; };
 		65B8C9281EC0BE62009439D9 /* InAppReceiptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptTests.swift; sourceTree = "<group>"; };
 		65BB6CE71DDB018900218A0B /* SwiftyStoreKit+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftyStoreKit+Types.swift"; sourceTree = "<group>"; };
+		65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptVerificator.swift; sourceTree = "<group>"; };
 		65F70AC61E2ECBB300BF040D /* PaymentTransactionObserverFake.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentTransactionObserverFake.swift; sourceTree = "<group>"; };
 		65F70AC81E2EDC3700BF040D /* PaymentsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentsController.swift; sourceTree = "<group>"; };
 		65F7DF681DCD4DF000835D30 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -306,6 +310,7 @@
 				650307F71E317BCF001332A4 /* CompleteTransactionsController.swift */,
 				C4083C561C2AB0A900295248 /* InAppReceiptRefreshRequest.swift */,
 				C4A7C7621C29B8D00053ED64 /* InAppReceipt.swift */,
+				65E9E0781ECADF5E005CF7B4 /* InAppReceiptVerificator.swift */,
 				1592CD4F1E27756500D321E6 /* AppleReceiptValidator.swift */,
 				653722801DB8282600C8F944 /* SKProduct+LocalizedPrice.swift */,
 				C40C680F1C29414C00B60B7E /* OS.swift */,
@@ -558,6 +563,7 @@
 					};
 					6502F5FD1B985833004E342D = {
 						CreatedOnToolsVersion = 7.0;
+						DevelopmentTeam = M54ZVB688G;
 						LastSwiftMigration = 0800;
 						ProvisioningStyle = Automatic;
 					};
@@ -710,6 +716,7 @@
 				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 */,
@@ -740,6 +747,7 @@
 				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 */,
@@ -786,6 +794,7 @@
 				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 */,
@@ -1015,7 +1024,7 @@
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				DEVELOPMENT_TEAM = "";
+				DEVELOPMENT_TEAM = M54ZVB688G;
 				INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit-iOS-Demo/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -1031,7 +1040,7 @@
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				DEVELOPMENT_TEAM = "";
+				DEVELOPMENT_TEAM = M54ZVB688G;
 				INFOPLIST_FILE = "$(SRCROOT)/SwiftyStoreKit-iOS-Demo/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";

+ 0 - 37
SwiftyStoreKit/InAppReceipt.swift

@@ -80,43 +80,6 @@ extension ReceiptItem {
 // MARK - receipt mangement
 internal class InAppReceipt {
 
-    static var appStoreReceiptUrl: URL? {
-        return Bundle.main.appStoreReceiptURL
-    }
-
-    static var appStoreReceiptData: Data? {
-        guard let receiptDataURL = appStoreReceiptUrl, let data = try? Data(contentsOf: receiptDataURL) else {
-            return nil
-        }
-        return data
-    }
-
-    // The base64 encoded receipt data.
-    static var appStoreReceiptBase64Encoded: String? {
-        return appStoreReceiptData?.base64EncodedString(options: [])
-    }
-
-    // https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
-
-    /**
-     *  - Parameter receiptVerifyURL: receipt verify url (default: Production)
-     *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
-     *  - Parameter session: the session used to make remote call.
-     *  - Parameter completion: handler for result
-     */
-    class func verify(using validator: ReceiptValidator,
-                      password autoRenewPassword: String? = nil,
-                      completion: @escaping (VerifyReceiptResult) -> Void) {
-
-        // If no receipt is present, validation fails.
-        guard let base64EncodedString = appStoreReceiptBase64Encoded else {
-            completion(.error(error: .noReceiptData))
-            return
-        }
-
-        validator.validate(receipt: base64EncodedString, password: autoRenewPassword, completion: completion)
-    }
-
     /**
      *  Verify the purchase of a Consumable or NonConsumable product in a receipt
      *  - Parameter productId: the product id of the purchase to verify

+ 94 - 0
SwiftyStoreKit/InAppReceiptVerificator.swift

@@ -0,0 +1,94 @@
+//
+//  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 {
+
+    static var appStoreReceiptUrl: URL? {
+        return Bundle.main.appStoreReceiptURL
+    }
+    
+    static 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 password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
+     *  - Parameter session: the session used to make remote call.
+     *  - Parameter completion: handler for result
+     */
+    public func verifyReceipt(using validator: ReceiptValidator, password: String? = nil, completion: @escaping (VerifyReceiptResult) -> Void) {
+        
+        if let receiptData = InAppReceiptVerificator.appStoreReceiptData {
+            
+            verify(receiptData: receiptData, using: validator, password: password, completion: completion)
+        } else {
+            
+            receiptRefreshRequest = InAppReceiptRefreshRequest.refresh { result in
+                
+                self.receiptRefreshRequest = nil
+                
+                switch result {
+                case .success:
+                    if let receiptData = InAppReceiptVerificator.appStoreReceiptData {
+                        self.verify(receiptData: receiptData, using: validator, password: password, completion: completion)
+                    } else {
+                        completion(.error(error: .noReceiptData))
+                    }
+                case .error(let e):
+                    completion(.error(error: .networkError(error: e)))
+                }
+            }
+        }
+    }
+    
+    // https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
+    
+    /**
+     *  - Parameter receiptData: encrypted receipt data
+     *  - Parameter validator: the validator to use
+     *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
+     *  - Parameter completion: handler for result
+     */
+    private func verify(receiptData: Data, using validator: ReceiptValidator, password: String? = nil, completion: @escaping (VerifyReceiptResult) -> Void) {
+     
+        // The base64 encoded receipt data.
+        let base64EncodedString = receiptData.base64EncodedString(options: [])
+
+        validator.validate(receipt: base64EncodedString, password: password) { result in
+            
+            DispatchQueue.main.async {
+                completion(result)
+            }
+        }
+    }
+}

+ 1 - 1
SwiftyStoreKit/SwiftyStoreKit+Types.swift

@@ -138,7 +138,7 @@ public struct ReceiptItem {
 public enum ReceiptError: Swift.Error {
     // No receipt data
     case noReceiptData
-    // No data receice
+    // No data received
     case noRemoteData
     // Error when encoding HTTP body into JSON
     case requestBodyEncodeError(error: Swift.Error)

+ 12 - 49
SwiftyStoreKit/SwiftyStoreKit.swift

@@ -30,13 +30,14 @@ public class SwiftyStoreKit {
 
     private let paymentQueueController: PaymentQueueController
 
-    private var receiptRefreshRequest: InAppReceiptRefreshRequest?
+    fileprivate let receiptVerificator: InAppReceiptVerificator
 
     init(productsInfoController: ProductsInfoController = ProductsInfoController(),
          paymentQueueController: PaymentQueueController = PaymentQueueController(paymentQueue: SKPaymentQueue.default())) {
 
         self.productsInfoController = productsInfoController
         self.paymentQueueController = paymentQueueController
+        self.receiptVerificator = InAppReceiptVerificator()
     }
 
     // MARK: Internal methods
@@ -83,24 +84,6 @@ public class SwiftyStoreKit {
         paymentQueueController.finishTransaction(transaction)
     }
 
-    func refreshReceipt(_ receiptProperties: [String : Any]? = nil, completion: @escaping (RefreshReceiptResult) -> Void) {
-        receiptRefreshRequest = InAppReceiptRefreshRequest.refresh(receiptProperties) { result in
-
-            self.receiptRefreshRequest = nil
-
-            switch result {
-            case .success:
-                if let appStoreReceiptData = InAppReceipt.appStoreReceiptData {
-                    completion(.success(receiptData: appStoreReceiptData))
-                } else {
-                    completion(.error(error: ReceiptError.noReceiptData))
-                }
-            case .error(let e):
-                completion(.error(error: e))
-            }
-        }
-    }
-
     // MARK: private methods
     private func purchase(product: SKProduct, quantity: Int, atomically: Bool, applicationUsername: String = "", completion: @escaping (PurchaseResult) -> Void) {
         guard SwiftyStoreKit.canMakePayments else {
@@ -152,7 +135,7 @@ public class SwiftyStoreKit {
 extension SwiftyStoreKit {
 
     // MARK: Singleton
-    private static let sharedInstance = SwiftyStoreKit()
+    fileprivate static let sharedInstance = SwiftyStoreKit()
 
     // MARK: Public methods - Purchases
     public class var canMakePayments: Bool {
@@ -191,12 +174,6 @@ extension SwiftyStoreKit {
 
         sharedInstance.finishTransaction(transaction)
     }
-
-    // After verifying receive and have `ReceiptError.NoReceiptData`, refresh receipt using this method
-    public class func refreshReceipt(_ receiptProperties: [String : Any]? = nil, completion: @escaping (RefreshReceiptResult) -> Void) {
-
-        sharedInstance.refreshReceipt(receiptProperties, completion: completion)
-    }
 }
 
 extension SwiftyStoreKit {
@@ -207,38 +184,28 @@ extension SwiftyStoreKit {
      * Return receipt data from the application bundle. This is read from Bundle.main.appStoreReceiptURL
      */
     public static var localReceiptData: Data? {
-        return InAppReceipt.appStoreReceiptData
+        return InAppReceiptVerificator.appStoreReceiptData
     }
 
     /**
      *  Verify application receipt
+     *  - Parameter validator: receipt validator to use
      *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
-     *  - Parameter session: the session used to make remote call.
      *  - Parameter completion: handler for result
      */
-    public class func verifyReceipt(
-        using validator: ReceiptValidator,
-        password: String? = nil,
-        completion:@escaping (VerifyReceiptResult) -> Void) {
+    public class func verifyReceipt(using validator: ReceiptValidator, password: String? = nil, completion: @escaping (VerifyReceiptResult) -> Void) {
 
-        InAppReceipt.verify(using: validator, password: password) { result in
-
-            DispatchQueue.main.async {
-                completion(result)
-            }
-        }
+        sharedInstance.receiptVerificator.verifyReceipt(using: validator, password: password, 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
      *  - return: either notPurchased or purchased
      */
-    public class func verifyPurchase(
-        productId: String,
-        inReceipt receipt: ReceiptInfo
-        ) -> VerifyPurchaseResult {
+    public class func verifyPurchase(productId: String, inReceipt receipt: ReceiptInfo) -> VerifyPurchaseResult {
+
         return InAppReceipt.verifyPurchase(productId: productId, inReceipt: receipt)
     }
 
@@ -250,12 +217,8 @@ extension SwiftyStoreKit {
      *  - Parameter validDuration: the duration of the subscription. Only required for non-renewable subscription.
      *  - return: either NotPurchased or Purchased / Expired with the expiry date found in the receipt
      */
-    public class func verifySubscription(
-        type: SubscriptionType,
-        productId: String,
-        inReceipt receipt: ReceiptInfo,
-        validUntil date: Date = Date()
-        ) -> VerifySubscriptionResult {
+    public class func verifySubscription(type: SubscriptionType, productId: String, inReceipt receipt: ReceiptInfo, validUntil date: Date = Date()) -> VerifySubscriptionResult {
+
         return InAppReceipt.verifySubscription(type: type, productId: productId, inReceipt: receipt, validUntil: date)
     }
 }