diff --git a/README.md b/README.md index 880424c3..6d96371c 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ let receiptString = receiptData.base64EncodedString(options: []) ```swift let appleValidator = AppleReceiptValidator(service: .production) -SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in +SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret", forceRefresh: false) { result in switch result { case .success(let receipt): print("Verify receipt Success: \(receipt)") @@ -272,6 +272,8 @@ SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secre } ``` +Note: you can specify `forceRefresh: true` to force SwiftyStoreKit to refresh the receipt with Apple, even if a local receipt is already stored. + ## Verifying purchases and subscriptions Once you have retrieved the receipt using the `verifyReceipt` method, you can verify your purchases and subscriptions by product identifier. diff --git a/SwiftyStoreKit/InAppReceiptVerificator.swift b/SwiftyStoreKit/InAppReceiptVerificator.swift index 58f4761f..e7389c18 100644 --- a/SwiftyStoreKit/InAppReceiptVerificator.swift +++ b/SwiftyStoreKit/InAppReceiptVerificator.swift @@ -48,15 +48,17 @@ class InAppReceiptVerificator: NSObject { * * If the receipt is available or is refreshed, validate it * - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format * - Parameter password: Your app’s shared secret (a hexadecimal string). Only used for receipts that contain auto-renewable subscriptions. + * - Parameter forceRefresh: If true, refreshes the receipt even if one already exists. * - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability) * - Parameter completion: handler for result */ public func verifyReceipt(using validator: ReceiptValidator, password: String? = nil, + forceRefresh: Bool, refresh: InAppReceiptRefreshRequest.ReceiptRefresh = InAppReceiptRefreshRequest.refresh, completion: @escaping (VerifyReceiptResult) -> Void) { - if let receiptData = appStoreReceiptData { + if let receiptData = appStoreReceiptData, forceRefresh == false { verify(receiptData: receiptData, using: validator, password: password, completion: completion) } else { diff --git a/SwiftyStoreKit/SwiftyStoreKit.swift b/SwiftyStoreKit/SwiftyStoreKit.swift index cb050487..2a2800bd 100644 --- a/SwiftyStoreKit/SwiftyStoreKit.swift +++ b/SwiftyStoreKit/SwiftyStoreKit.swift @@ -221,11 +221,12 @@ extension SwiftyStoreKit { * 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 forceRefresh: If true, refreshes the receipt even if one already exists. * - 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, forceRefresh: Bool = false, completion: @escaping (VerifyReceiptResult) -> Void) { - sharedInstance.receiptVerificator.verifyReceipt(using: validator, password: password, completion: completion) + sharedInstance.receiptVerificator.verifyReceipt(using: validator, password: password, forceRefresh: forceRefresh, completion: completion) } /** diff --git a/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift b/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift index 5bdbb055..0df5f7be 100644 --- a/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift +++ b/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift @@ -76,7 +76,7 @@ class InAppReceiptVerificatorTests: XCTestCase { let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil) var refreshCalled = false - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in refreshCalled = true return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback) @@ -95,7 +95,27 @@ class InAppReceiptVerificatorTests: XCTestCase { let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL) var refreshCalled = false - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + + refreshCalled = true + return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback) + + }) { _ in + + } + XCTAssertTrue(refreshCalled) + } + + func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_hasReceiptData_forceRefreshIsTrue_then_callsRefresh() { + + let testReceiptURL = makeReceiptURL() + writeReceiptData(to: testReceiptURL) + + let validator = TestReceiptValidator() + let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL) + + var refreshCalled = false + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: true, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in refreshCalled = true return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback) @@ -112,7 +132,7 @@ class InAppReceiptVerificatorTests: XCTestCase { let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil) let refreshError = NSError(domain: "", code: 0, userInfo: nil) - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in callback(.error(e: refreshError)) return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback) @@ -128,7 +148,7 @@ class InAppReceiptVerificatorTests: XCTestCase { let validator = TestReceiptValidator() let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil) - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in callback(.success) return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback) @@ -147,7 +167,7 @@ class InAppReceiptVerificatorTests: XCTestCase { let validator = TestReceiptValidator() let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil) - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in writeReceiptData(to: testReceiptURL) callback(.success) @@ -168,7 +188,7 @@ class InAppReceiptVerificatorTests: XCTestCase { let validator = TestReceiptValidator() let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL) - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in writeReceiptData(to: testReceiptURL) callback(.success) @@ -182,7 +202,7 @@ class InAppReceiptVerificatorTests: XCTestCase { } // MARK: non-refresh tests (receipt url and data are set) - func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_hasReceiptData_then_refreshNotCalled_validateIsCalled() { + func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_hasReceiptData_forceRefreshIsFalse_then_refreshNotCalled_validateIsCalled() { let testReceiptURL = makeReceiptURL() writeReceiptData(to: testReceiptURL) @@ -190,7 +210,7 @@ class InAppReceiptVerificatorTests: XCTestCase { let validator = TestReceiptValidator() let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL) - verificator.verifyReceipt(using: validator, password: nil, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in + verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in XCTFail("refresh should not be called if we already have a receipt") return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)