bizz84 / SwiftyStoreKit

Lightweight In App Purchases Swift framework for iOS 8.0+, tvOS 9.0+ and macOS 10.10+ ⛺
MIT License
6.54k stars 794 forks source link

SwiftyStoreKit.refreshReceipt() should not be removed #223

Closed hlung closed 7 years ago

hlung commented 7 years ago

Platform

In app purchase type

Environment

Version

ℹ Please replace this with the version of SwiftyStoreKit you're using. 10.1

Report

This pull request https://github.com/bizz84/SwiftyStoreKit/pull/213 removed SwiftyStoreKit.refreshReceipt(). But I need it for refreshing receipt and send it to my server for validation. I think it is a valid use case.

vovkaprigarin commented 7 years ago

Yep. I didn't found this method in new version. Case: If you change apple id - you will need update receipt and after then you will send to my server. I need this function! :)

bizz84 commented 7 years ago

@hlung @vovkasmprigarin Currently, the receipt is refreshed automatically if it's missing when you call verifyReceipt.

The intention is to let SwiftyStoreKit handle this for you.

Rather than restoring the old refreshReceipt() method, I think it would be best to pass a new forceRefresh parameter to verifyReceipt():

verifyReceipt(using validator: ReceiptValidator, 
                       password: String? = nil, 
                       forceReceipt: Bool = false, 
                       completion: @escaping (VerifyReceiptResult) -> Void)

This way, SwiftyStoreKit will first refresh the receipt, then use it with your ReceiptValidator.

Makes sense?

vovkaprigarin commented 7 years ago

@bizz84 No. I send receipt data to my server for validation.

hlung commented 7 years ago

@bizz84 Yes it make sense if i let apple validate receipt for me. But my app does validation on server (need to send actual receipt data). Calling SKRefreshReceipt request is troblesome because of the delegate pattern. Having SwiftyStoreKit handle this with callback closure is much easier to use ;)

bizz84 commented 7 years ago

@vovkasmprigarin @hlung If you use AppleReceiptValidator like in the README, then you're validating the receipt with Apple.

However, you don't have to. You can write your own validator that takes the receipt data as a string, and posts it to your own server. Example:

class CustomReceiptValidator: ReceiptValidator {
    func validate(receipt: String, password autoRenewPassword: String?, completion: @escaping (VerifyReceiptResult) -> Void) {
        // encode string, send to your own server, call completion when processed.
    }
}

You can then call validateReceipt() like so:

let customValidator = CustomReceiptValidator()
SwiftyStoreKit.verifyReceipt(using: customValidator, password: "your-shared-secret") { result in
    switch result {
    case .success(let receipt):
        // Verify the purchase of Consumable or NonConsumable
    case .error(let error):
        // Handle error
    }
}

I can add a forceRefresh parameter if needed, but other than this you shouldn't need anything else to do your own custom validation.

bizz84 commented 7 years ago

@vovkasmprigarin I have opened #224 to add a forceRefresh parameter, however I'm not convinced this is necessary.

If you already have a local receipt and you change the Apple ID, are you sure the app doesn't update the receipt automatically?

bizz84 commented 7 years ago

This is now implemented and available on version 0.10.3.

Closing the issue for now. Feel free to ask more questions if needed.

vovkaprigarin commented 7 years ago

@bizz84 yep. If you change the AppleID, the Receipt doesn't update automatically:(

CustomReceiptValidator send data to apple server to validate. It's not correct for me. I send receiptData to my server, and after then server send receiptData to Apple server for validation.

force update may be will help for people, but will not for me:(

Ok. I will use last pod version with refresh receipt function. Thanks for your answers :)

bizz84 commented 7 years ago

@vovkasmprigarin To clarify, AppleReceiptValidator sends the data to Apple.

I am proposing to write your own custom validator to post data to your server. See my answer above.

hlung commented 7 years ago

In my case, I need to pass user id to my backend. Since ReceiptValidator protocol doesn't allow me to add custom data, I need to pass user id to my custom validator at instantiation time. Not very clean.

I think I can just create a SKReceiptRefreshRequest wrapper. May be pull some code from InAppReceiptRefreshRequest. Will share my code later. ;)

vxst commented 7 years ago

We also need to only verify receipt at server, so the old refreshReceipt is much more handy than implement a custom class for that job.

We believe it's a common case. Anyway, why do we need to use a SwiftyStoreKit if everything need to be a new class and delegate? Apple's Storekit will just be fine.

bizz84 commented 7 years ago

@hlung I think passing any custom data to your ReceiptValidator initialiser should be fine, as you could just create it on the fly and pass it to verifyReceipt.

@vxst You own the logic for receipt verification with your server, so it makes sense to implement it in a class and pass it to SwiftyStoreKit.

I see that a few people seem confused by this. Is the documentation not clear?