Browse Source

Use receipt URL enum instead of boolean in verify method
Better doc disposition for receipt
Fix OS X demo app when verifying receipt, do not exit before user close alert message

phimage 9 years ago
parent
commit
10b6bdfc7e

+ 12 - 12
SwiftStoreOSXDemo/Base.lproj/Main.storyboard

@@ -692,8 +692,8 @@
                                                 <rect key="frame" x="0.0" y="0.0" width="254" height="176"/>
                                                 <rect key="frame" x="0.0" y="0.0" width="254" height="176"/>
                                                 <autoresizingMask key="autoresizingMask"/>
                                                 <autoresizingMask key="autoresizingMask"/>
                                                 <subviews>
                                                 <subviews>
-                                                    <button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ypp-fu-oEb">
-                                                        <rect key="frame" x="80" y="103" width="90" height="32"/>
+                                                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ypp-fu-oEb">
+                                                        <rect key="frame" x="82" y="103" width="90" height="32"/>
                                                         <buttonCell key="cell" type="push" title="Get Info" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vSi-fu-wrI">
                                                         <buttonCell key="cell" type="push" title="Get Info" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vSi-fu-wrI">
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <font key="font" metaFont="system"/>
                                                             <font key="font" metaFont="system"/>
@@ -702,16 +702,16 @@
                                                             <action selector="getInfo1:" target="XfG-lQ-9wD" id="PTC-RY-Aom"/>
                                                             <action selector="getInfo1:" target="XfG-lQ-9wD" id="PTC-RY-Aom"/>
                                                         </connections>
                                                         </connections>
                                                     </button>
                                                     </button>
-                                                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="23w-eX-lGC">
-                                                        <rect key="frame" x="102" y="139" width="45" height="17"/>
+                                                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="23w-eX-lGC">
+                                                        <rect key="frame" x="105" y="139" width="45" height="17"/>
                                                         <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="5 days" id="U2h-U7-cdn">
                                                         <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="5 days" id="U2h-U7-cdn">
                                                             <font key="font" metaFont="system"/>
                                                             <font key="font" metaFont="system"/>
                                                             <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                                                             <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                                         </textFieldCell>
                                                         </textFieldCell>
                                                     </textField>
                                                     </textField>
-                                                    <button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Hez-z0-TRG">
-                                                        <rect key="frame" x="76" y="70" width="98" height="32"/>
+                                                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Hez-z0-TRG">
+                                                        <rect key="frame" x="78" y="70" width="98" height="32"/>
                                                         <buttonCell key="cell" type="push" title="Purchase" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="5bl-kX-gwW">
                                                         <buttonCell key="cell" type="push" title="Purchase" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="5bl-kX-gwW">
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <font key="font" metaFont="system"/>
                                                             <font key="font" metaFont="system"/>
@@ -734,16 +734,16 @@
                                                 <rect key="frame" x="255" y="0.0" width="225" height="176"/>
                                                 <rect key="frame" x="255" y="0.0" width="225" height="176"/>
                                                 <autoresizingMask key="autoresizingMask"/>
                                                 <autoresizingMask key="autoresizingMask"/>
                                                 <subviews>
                                                 <subviews>
-                                                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gj2-Z2-1qo">
-                                                        <rect key="frame" x="84" y="139" width="53" height="17"/>
+                                                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gj2-Z2-1qo">
+                                                        <rect key="frame" x="86" y="139" width="53" height="17"/>
                                                         <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="10 days" id="XkC-cw-jpP">
                                                         <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="10 days" id="XkC-cw-jpP">
                                                             <font key="font" metaFont="system"/>
                                                             <font key="font" metaFont="system"/>
                                                             <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                                                             <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                                         </textFieldCell>
                                                         </textFieldCell>
                                                     </textField>
                                                     </textField>
-                                                    <button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="32D-7s-IOR">
-                                                        <rect key="frame" x="66" y="103" width="90" height="32"/>
+                                                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="32D-7s-IOR">
+                                                        <rect key="frame" x="68" y="103" width="90" height="32"/>
                                                         <buttonCell key="cell" type="push" title="Get Info" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="F8O-DF-BZX">
                                                         <buttonCell key="cell" type="push" title="Get Info" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="F8O-DF-BZX">
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <font key="font" metaFont="system"/>
                                                             <font key="font" metaFont="system"/>
@@ -752,8 +752,8 @@
                                                             <action selector="getInfo2:" target="XfG-lQ-9wD" id="u4g-Qb-RyE"/>
                                                             <action selector="getInfo2:" target="XfG-lQ-9wD" id="u4g-Qb-RyE"/>
                                                         </connections>
                                                         </connections>
                                                     </button>
                                                     </button>
-                                                    <button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GkW-aD-XKc">
-                                                        <rect key="frame" x="62" y="70" width="98" height="32"/>
+                                                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="GkW-aD-XKc">
+                                                        <rect key="frame" x="64" y="70" width="98" height="32"/>
                                                         <buttonCell key="cell" type="push" title="Purchase" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="TDW-1n-a4d">
                                                         <buttonCell key="cell" type="push" title="Purchase" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="TDW-1n-a4d">
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                             <font key="font" metaFont="system"/>
                                                             <font key="font" metaFont="system"/>

+ 7 - 5
SwiftStoreOSXDemo/ViewController.swift

@@ -18,17 +18,18 @@ class ViewController: NSViewController {
         super.viewDidLoad()
         super.viewDidLoad()
     }
     }
 
 
-    func showMessage(title: String, message: String) {
-
+    func showMessage(title: String, message: String, handler: ((NSModalResponse) -> Void)? = nil) {
         let alert: NSAlert = NSAlert()
         let alert: NSAlert = NSAlert()
         alert.messageText = title
         alert.messageText = title
         alert.informativeText = message
         alert.informativeText = message
         alert.alertStyle = NSAlertStyle.InformationalAlertStyle
         alert.alertStyle = NSAlertStyle.InformationalAlertStyle
         if let window = NSApplication.sharedApplication().keyWindow {
         if let window = NSApplication.sharedApplication().keyWindow {
             alert.beginSheetModalForWindow(window) { (response: NSModalResponse) in
             alert.beginSheetModalForWindow(window) { (response: NSModalResponse) in
+                handler?(response)
             }
             }
         } else {
         } else {
-            alert.runModal()
+            let response = alert.runModal()
+            handler?(response)
         }
         }
         return
         return
     }
     }
@@ -115,8 +116,9 @@ class ViewController: NSViewController {
                 break
                 break
             case .Error(let error):
             case .Error(let error):
                 print("Verify receipt Failed: \(error)")
                 print("Verify receipt Failed: \(error)")
-                self.showMessage("Receipt verification failed", message: "The application will exit to create receipt data. You must have signed the application with your developper id to test and be outside of XCode")
-                exit(ReceiptExitCode.NotValid.rawValue)
+                self.showMessage("Receipt verification failed", message: "The application will exit to create receipt data. You must have signed the application for app store with your developper id to test") { response in
+                    exit(ReceiptExitCode.NotValid.rawValue)
+                }
                 break
                 break
             }
             }
         }
         }

+ 79 - 61
SwiftyStoreKit/InAppReceipt.swift

@@ -25,7 +25,7 @@
 
 
 import Foundation
 import Foundation
 
 
-// Info for receipt return by server
+// Info for receipt returned by server
 public typealias ReceiptInfo = [String: AnyObject]
 public typealias ReceiptInfo = [String: AnyObject]
 
 
 // MARK: - Enumeration
 // MARK: - Enumeration
@@ -35,87 +35,105 @@ public enum ValidReceiptResultType {
     case Error(error: ReceiptError)
     case Error(error: ReceiptError)
 }
 }
 
 
-public enum ReceiptError : ErrorType {
+// Error when managing receipt
+public enum ReceiptError: ErrorType {
+    // No receipt data
     case NoReceiptData
     case NoReceiptData
+    // No data receice
     case NoRemoteData
     case NoRemoteData
+    // Error when encoding HTTP body into JSON
     case RequestBodyEncodeError(error: ErrorType)
     case RequestBodyEncodeError(error: ErrorType)
-    case JSONDecodeError(string: String?)
+    // Error when proceeding request
     case NetworkError(error: ErrorType)
     case NetworkError(error: ErrorType)
-    case AppStore(status: Int)
+    // Error when decoding response
+    case JSONDecodeError(string: String?)
+    // Receive invalid - bad status returned
     case ReceiptInvalid(receipt: ReceiptInfo, status: ReceiptStatus)
     case ReceiptInvalid(receipt: ReceiptInfo, status: ReceiptStatus)
 }
 }
 
 
 // Status code returned by remote server
 // Status code returned by remote server
 // see Table 2-1  Status codes
 // see Table 2-1  Status codes
 public enum ReceiptStatus: Int {
 public enum ReceiptStatus: Int {
-    case Unknown = -2 // Not decodable status
-    case None = -1 // No status returned
-
-    case Valid = 0 // valid status
-
-    case JSONNotReadable = 21000 // The App Store could not read the JSON object you provided.
-    case MalformedOrMissingData = 21002 // The data in the receipt-data property was malformed or missing.
-
-    case ReceiptCouldNotBeAuthenticated = 21003 // The receipt could not be authenticated.
-    case SecretNotMatching = 21004 // The shared secret you provided does not match the shared secret on file for your account.
-    case ReceiptServerUnavailable = 21005 // The receipt server is not currently available.
-    case SubscriptionExpired = 21006 // 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 TestReceipt = 21007 //  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 ProductionEnvironment = 21008 // This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.
+    // Not decodable status
+    case Unknown = -2
+    // No status returned
+    case None = -1
+    // valid statu
+    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
 // 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 {
-    case bundle_id // Bundle Identifier. This corresponds to the value of CFBundleIdentifier in the Info.plist file.
-    case application_version //  The app’s version number.This corresponds to the value of CFBundleVersion (in iOS) or CFBundleShortVersionString (in OS X) in the Info.plist.
-    case  original_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 creation_date // The date when the app receipt was created.
-    case expiration_date // The date that the app receipt expires. This key is present only for apps purchased through the Volume Purchase Program.
-
-    case in_app // The receipt for an in-app purchase.
+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 {
     public enum InApp {
-
-        case quantity// The number of items purchased. This value corresponds to the quantity property of the SKPayment object stored in the transaction’s payment property.
-
-        case product_id // 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 transaction_id // The transaction identifier of the item that was purchased. This value corresponds to the transaction’s transactionIdentifier property.
-
-        case original_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 purchase_date // The date and time that the item was purchased. This value corresponds to the transaction’s transactionDate property.
-
-        case original_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 expires_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 cancellation_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.
-
+        // 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)
         #if os(iOS)
-        case app_item_id // 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.
+        // 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
         #endif
-
-        case version_external_identifier // An arbitrary number that uniquely identifies a revision of your application. This key is not present for receipts created in the test environment.
-        
-        case web_order_line_item_id // The primary key for identifying subscription purchases.
+        // 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
     }
     }
 }
 }
 
 
-// URL used to verify
+// URL used to verify remotely receipt
 public enum ReceiptVerifyURL: String {
 public enum ReceiptVerifyURL: String {
     case Production = "https://buy.itunes.apple.com/verifyReceipt"
     case Production = "https://buy.itunes.apple.com/verifyReceipt"
     case Test = "https://sandbox.itunes.apple.com/verifyReceipt"
     case Test = "https://sandbox.itunes.apple.com/verifyReceipt"
 }
 }
-extension Bool {
-    var toReceiptVerifyURL: ReceiptVerifyURL {
-        return self ? .Test : .Production
-    }
-}
 
 
 #if os(OSX)
 #if os(OSX)
     public enum ReceiptExitCode: Int32 {
     public enum ReceiptExitCode: Int32 {
-        case NotValid = 173 // 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
+        // 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
 #endif
 
 
@@ -130,7 +148,6 @@ internal class InAppReceipt {
         if let receiptDataURL = URL, data = NSData(contentsOfURL: receiptDataURL) {
         if let receiptDataURL = URL, data = NSData(contentsOfURL: receiptDataURL) {
             return data
             return data
         }
         }
-        print(NSBundle.mainBundle().appStoreReceiptURL)
         return nil
         return nil
     }
     }
 
 
@@ -142,13 +159,13 @@ internal class InAppReceipt {
     // https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
     // https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
 
 
    /**
    /**
-    *  - Parameter test: if true use test environment remote URL otherwise production one (default: true)
+    *  - Parameter receiptVerifyURL: receipt verify url (default: Test)
     *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
     *  - 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 session: the session used to make remote call.
     *  - Parameter completion: handler for result
     *  - Parameter completion: handler for result
     */
     */
     class func verify(
     class func verify(
-        test: Bool = true,
+        receiptVerifyURL url: ReceiptVerifyURL = .Test,
         password autoRenewPassword: String? = nil,
         password autoRenewPassword: String? = nil,
         session: NSURLSession = NSURLSession.sharedSession(),
         session: NSURLSession = NSURLSession.sharedSession(),
         completion:(result: ValidReceiptResultType) -> ()) {
         completion:(result: ValidReceiptResultType) -> ()) {
@@ -160,7 +177,7 @@ internal class InAppReceipt {
             }
             }
 
 
             // Create request
             // Create request
-            let storeURL = NSURL(string: test.toReceiptVerifyURL.rawValue)! // safe (until no more)
+            let storeURL = NSURL(string: url.rawValue)! // safe (until no more)
             let storeRequest = NSMutableURLRequest(URL: storeURL)
             let storeRequest = NSMutableURLRequest(URL: storeURL)
             storeRequest.HTTPMethod = "POST"
             storeRequest.HTTPMethod = "POST"
 
 
@@ -203,11 +220,12 @@ internal class InAppReceipt {
 
 
                 // get status from info
                 // get status from info
                 if let status = receiptInfo["status"] as? Int {
                 if let status = receiptInfo["status"] as? Int {
-                    if status == ReceiptStatus.Valid.rawValue {
+                    let receiptStatus = ReceiptStatus(rawValue: status) ?? ReceiptStatus.Unknown
+                    if receiptStatus.isValid {
                         completion(result: .Success(receipt: receiptInfo))
                         completion(result: .Success(receipt: receiptInfo))
                     }
                     }
                     else {
                     else {
-                        completion(result: .Error(error: .ReceiptInvalid(receipt: receiptInfo, status: ReceiptStatus(rawValue: status) ?? ReceiptStatus.Unknown)))
+                        completion(result: .Error(error: .ReceiptInvalid(receipt: receiptInfo, status: receiptStatus)))
                     }
                     }
                 }
                 }
                 else {
                 else {

+ 5 - 4
SwiftyStoreKit/SwiftyStoreKit.swift

@@ -117,20 +117,22 @@ public class SwiftyStoreKit {
     }
     }
 
 
     /**
     /**
-     *  - Parameter test: if true use test environment remote URL otherwise production one (default: true)
+     *  Verify application receipt
+     *  - Parameter receiptVerifyURL: receipt verify url (default: Test)
      *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
      *  - 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 session: the session used to make remote call.
      *  - Parameter completion: handler for result
      *  - Parameter completion: handler for result
      */
      */
     public class func verifyReceipt(
     public class func verifyReceipt(
-        test: Bool = true,
+        receiptVerifyURL url: ReceiptVerifyURL = .Test,
         password: String? = nil,
         password: String? = nil,
         session: NSURLSession = NSURLSession.sharedSession(),
         session: NSURLSession = NSURLSession.sharedSession(),
         completion:(result: ValidReceiptResultType) -> ()) {
         completion:(result: ValidReceiptResultType) -> ()) {
-            InAppReceipt.verify(test, password: password, session: session, completion: completion)
+            InAppReceipt.verify(receiptVerifyURL: url, password: password, session: session, completion: completion)
     }
     }
 
 
     #if os(iOS)
     #if os(iOS)
+    // After verifying receive and have `ReceiptError.NoReceiptData`, refresh receipt using this method
     public class func receiptRefresh(receiptProperties: [String : AnyObject]? = nil, completion: (result: RefreshReceiptResultType) -> ()) {
     public class func receiptRefresh(receiptProperties: [String : AnyObject]? = nil, completion: (result: RefreshReceiptResultType) -> ()) {
         sharedInstance.receiptRefreshRequest = InAppReceiptRefreshRequest.refresh(receiptProperties) { result in
         sharedInstance.receiptRefreshRequest = InAppReceiptRefreshRequest.refresh(receiptProperties) { result in
 
 
@@ -149,7 +151,6 @@ public class SwiftyStoreKit {
                 break
                 break
             }
             }
         }
         }
-
     }
     }
     #endif
     #endif