فهرست منبع

Merge pull request #100 from bizz84/feature/local-receipt-data

Allow to retrieve local receipt data
Andrea Bizzotto 8 سال پیش
والد
کامیت
ec21a6cae6

+ 10 - 2
README.md

@@ -93,6 +93,14 @@ SwiftyStoreKit.restorePurchases() { results in
 }
 }
 ```
 ```
 
 
+### Retrieve local receipt
+
+```swift
+let receiptData = SwiftyStoreKit.localReceiptData
+let receiptString = receiptData.base64EncodedString
+// do your receipt validation here
+```
+
 ### Verify Receipt
 ### Verify Receipt
 
 
 ```swift
 ```swift
@@ -107,8 +115,8 @@ SwiftyStoreKit.verifyReceipt(password: "your-shared-secret") { result in
 func refreshReceipt() {
 func refreshReceipt() {
     SwiftyStoreKit.refreshReceipt { result in
     SwiftyStoreKit.refreshReceipt { result in
         switch result {
         switch result {
-        case .success:
-            print("Receipt refresh success")
+        case .success(let receiptData):
+            print("Receipt refresh success: \(receiptData.base64EncodedString)")
         case .error(let error):
         case .error(let error):
             print("Receipt refresh failed: \(error)")
             print("Receipt refresh failed: \(error)")
         }
         }

+ 17 - 1
SwiftyStoreDemo/AppDelegate.swift

@@ -32,11 +32,27 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 
 
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
 
 
+        verifyReceipt()
+
         completeIAPTransactions()
         completeIAPTransactions()
-        
+
         return true
         return true
     }
     }
     
     
+    func verifyReceipt() {
+        
+        SwiftyStoreKit.verifyReceipt(password: "your-shared-secret") { result in
+            switch result {
+            case .success(let receipt):
+                print("\(receipt)")
+            case .error(let error):
+                if case .noReceiptData = error {
+                    SwiftyStoreKit.refreshReceipt { result in }
+                }
+            }
+        }
+    }
+    
     func completeIAPTransactions() {
     func completeIAPTransactions() {
         
         
         SwiftyStoreKit.completeTransactions() { completedTransactions in
         SwiftyStoreKit.completeTransactions() { completedTransactions in

+ 5 - 5
SwiftyStoreDemo/ViewController.swift

@@ -148,7 +148,7 @@ class ViewController: UIViewController {
 
 
     func refreshReceipt() {
     func refreshReceipt() {
 
 
-        SwiftyStoreKit.refreshReceipt { (result) -> () in
+        SwiftyStoreKit.refreshReceipt { result in
 
 
             self.showAlert(self.alertForRefreshReceipt(result))
             self.showAlert(self.alertForRefreshReceipt(result))
         }
         }
@@ -277,12 +277,12 @@ extension ViewController {
 
 
     func alertForRefreshReceipt(_ result: SwiftyStoreKit.RefreshReceiptResult) -> UIAlertController {
     func alertForRefreshReceipt(_ result: SwiftyStoreKit.RefreshReceiptResult) -> UIAlertController {
         switch result {
         switch result {
-        case .success:
-            print("Receipt refresh Success")
-            return self.alertWithTitle("Receipt refreshed", message: "Receipt refreshed successfully")
+        case .success(let receiptData):
+            print("Receipt refresh Success: \(receiptData.base64EncodedString)")
+            return alertWithTitle("Receipt refreshed", message: "Receipt refreshed successfully")
         case .error(let error):
         case .error(let error):
             print("Receipt refresh Failed: \(error)")
             print("Receipt refresh Failed: \(error)")
-            return self.alertWithTitle("Receipt refresh failed", message: "Receipt refresh failed")
+            return alertWithTitle("Receipt refresh failed", message: "Receipt refresh failed")
         }
         }
     }
     }
 
 

+ 16 - 16
SwiftyStoreKit/InAppReceipt.swift

@@ -154,30 +154,30 @@ internal class InAppReceipt {
         case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
         case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
     }
     }
 
 
-    static var URL: Foundation.URL? {
+    static var appStoreReceiptUrl: URL? {
         return Bundle.main.appStoreReceiptURL
         return Bundle.main.appStoreReceiptURL
     }
     }
 
 
-    static var data: Data? {
-        if let receiptDataURL = URL, let data = try? Data(contentsOf: receiptDataURL) {
-            return data
+    static var appStoreReceiptData: Data? {
+        guard let receiptDataURL = appStoreReceiptUrl, let data = try? Data(contentsOf: receiptDataURL) else {
+            return nil
         }
         }
-        return nil
+        return data
     }
     }
 
 
     // The base64 encoded receipt data.
     // The base64 encoded receipt data.
-    static var base64EncodedString: String? {
-        return data?.base64EncodedString(options: [])
+    static var appStoreReceiptBase64Encoded: String? {
+        return appStoreReceiptData?.base64EncodedString(options: [])
     }
     }
 
 
     // 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 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
-    */
+    /**
+     *  - 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(
     class func verify(
         urlType: VerifyReceiptURLType = .production,
         urlType: VerifyReceiptURLType = .production,
         password autoRenewPassword: String? = nil,
         password autoRenewPassword: String? = nil,
@@ -185,18 +185,18 @@ internal class InAppReceipt {
         completion: @escaping (SwiftyStoreKit.VerifyReceiptResult) -> ()) {
         completion: @escaping (SwiftyStoreKit.VerifyReceiptResult) -> ()) {
 
 
             // If no receipt is present, validation fails.
             // If no receipt is present, validation fails.
-            guard let base64EncodedString = self.base64EncodedString else {
+            guard let base64EncodedString = appStoreReceiptBase64Encoded else {
                 completion(.error(error: .noReceiptData))
                 completion(.error(error: .noReceiptData))
                 return
                 return
             }
             }
 
 
             // Create request
             // Create request
-            let storeURL = Foundation.URL(string: urlType.rawValue)! // safe (until no more)
+            let storeURL = URL(string: urlType.rawValue)! // safe (until no more)
             let storeRequest = NSMutableURLRequest(url: storeURL)
             let storeRequest = NSMutableURLRequest(url: storeURL)
             storeRequest.httpMethod = "POST"
             storeRequest.httpMethod = "POST"
 
 
 
 
-            let requestContents :NSMutableDictionary = [ "receipt-data" : base64EncodedString]
+            let requestContents: NSMutableDictionary = [ "receipt-data" : base64EncodedString ]
             // password if defined
             // password if defined
             if let password = autoRenewPassword {
             if let password = autoRenewPassword {
                 requestContents.setValue(password, forKey: "password")
                 requestContents.setValue(password, forKey: "password")

+ 12 - 4
SwiftyStoreKit/SwiftyStoreKit.swift

@@ -77,7 +77,7 @@ public class SwiftyStoreKit {
         public let restoreFailedProducts: [(Swift.Error, String?)]
         public let restoreFailedProducts: [(Swift.Error, String?)]
     }
     }
     public enum RefreshReceiptResult {
     public enum RefreshReceiptResult {
-        case success
+        case success(receiptData: Data)
         case error(error: Error)
         case error(error: Error)
     }
     }
     public struct CompletedTransaction {
     public struct CompletedTransaction {
@@ -152,6 +152,13 @@ public class SwiftyStoreKit {
         }
         }
     }
     }
 
 
+    /**
+     * Return receipt data from the application bundle. This is read from Bundle.main.appStoreReceiptURL
+     */
+    public static var localReceiptData: Data? {
+        return InAppReceipt.appStoreReceiptData
+    }
+    
     /**
     /**
      *  Verify application receipt
      *  Verify application receipt
      *  - 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).
@@ -209,10 +216,11 @@ public class SwiftyStoreKit {
 
 
             switch result {
             switch result {
             case .success:
             case .success:
-                if InAppReceipt.data == nil {
+                if let appStoreReceiptData = InAppReceipt.appStoreReceiptData {
+                    completion(.success(receiptData: appStoreReceiptData))
+                }
+                else {
                     completion(.error(error: ReceiptError.noReceiptData))
                     completion(.error(error: ReceiptError.noReceiptData))
-                } else {
-                    completion(.success)
                 }
                 }
             case .error(let e):
             case .error(let e):
                 completion(.error(error: e))
                 completion(.error(error: e))

+ 17 - 2
SwiftyStoreOSXDemo/ViewController.swift

@@ -95,7 +95,7 @@ class ViewController: NSViewController {
 
 
             self.showAlert(self.alertForVerifyReceipt(result)) { response in
             self.showAlert(self.alertForVerifyReceipt(result)) { response in
 
 
-                SwiftyStoreKit.refreshReceipt()
+                self.refreshReceipt()
             }
             }
         }
         }
     }
     }
@@ -131,8 +131,11 @@ class ViewController: NSViewController {
             }
             }
         }
         }
     }
     }
-    
 
 
+    func refreshReceipt() {
+        
+        SwiftyStoreKit.refreshReceipt()
+    }
 
 
 }
 }
 
 
@@ -253,5 +256,17 @@ extension ViewController {
             return alertWithTitle("Not purchased", message: "This product has never been purchased")
             return alertWithTitle("Not purchased", message: "This product has never been purchased")
         }
         }
     }
     }
+    
+    func alertForRefreshReceipt(_ result: SwiftyStoreKit.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")
+        }
+    }
+
 }
 }