MKStoreKit icon indicating copy to clipboard operation
MKStoreKit copied to clipboard

Release builds used via TestFlight will verify receipts against the wrong server

Open warpling opened this issue 10 years ago • 10 comments

Release builds will attempt to verify receipts against the production verification server, but release builds distributed via TestFlight should validate against the Sandbox server. Verifying sandbox receipts against the production server results in the error:

Error Domain=com.mugunthkumar.mkstorekit Code=21007 "This receipt is from the test environment." UserInfo={NSLocalizedDescription=This receipt is from the test environment.}

Apparently Apple's recommended method of handling this is to first attempt to validate against the production server and if that fails with error code 21007, try the request again with the Sandbox server. This should definitely make it into a future release! :)

warpling avatar Dec 14 '15 05:12 warpling

Hello @warpling

Do you have the code to fix it?

Regards

josueruiz7 avatar Jan 20 '16 02:01 josueruiz7

Yes!

Again the steps to handling the Sandbox are as follows:

  1. Try to hit the production server
  2. Fail, and recording when we get the 21007 error code
  3. Try again with the sandbox server (and thereon out)

Tweaks to make

I first added the private ivar inSandbox to MKStoreKit

@interface MKStoreKit (/*Private Methods*/) <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@property (readwrite) NSMutableDictionary *purchaseRecord;
@property (readwrite) BOOL inSandbox;
@end

Then in startValidatingAppStoreReceiptWithCompletionHandler I replaced the normal assignment to storeRequest with the following. This way future requests will immediately use the sandbox.

    NSMutableURLRequest *storeRequest;
    if (self.inSandbox) {
        storeRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kSandboxServer]];
    } else {
        storeRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kLiveServer]];
    }

Then I updated startValidatingReceiptsAndUpdateLocalStore like so. This way after the first failure we try again on the sandbox and continue to use the sandbox.

- (void)startValidatingReceiptsAndUpdateLocalStore {
    [self startValidatingAppStoreReceiptWithCompletionHandler:^(NSArray *receipts, NSError *error) {
        if (error) {
            // Receipt was from Sandbox
            if (error.code == 21007) {
                // Switch to using the Sandbox server here on out
                self.inSandbox = YES;
                // Restart validation
                [self startValidatingReceiptsAndUpdateLocalStore];
            }
            // If the error was anything else we'll treat it like an actual error/failure
            else {
                [[NSNotificationCenter defaultCenter] postNotificationName:kMKStoreKitReceiptValidationFailedNotification object:error];
            }
        } else {

warpling avatar Jan 20 '16 04:01 warpling

it works perfect! Thank you!

josueruiz7 avatar Jan 20 '16 17:01 josueruiz7

😊 I hope this can help others. I'd make a PR but it seems like the project isn't getting any merge love these days.

~Ryan

On Jan 20, 2016, 9:53 AM -0800, [email protected], wrote:

it works perfect! Thank you!

— Reply to this email directly orview it on GitHub(https://github.com/MugunthKumar/MKStoreKit/issues/255#issuecomment-173303301).

warpling avatar Jan 20 '16 18:01 warpling

@warpling I have an issue, maybe you can help me, I am trying to validate:

if([[MKStoreKit sharedKit] isProductPurchased:ID]) { }

But it seems that store cache, because when I first log in with an appleid that already has buy the product , it works perfect, but when I log out and log in with other appleId that has not bought the product, THIS VALIDATION still return true.

Did you get this issue? :(

Thanks.

josueruiz7 avatar Jan 21 '16 00:01 josueruiz7

Yikes, I've run into lots of weird issues with the Sandbox I'm afraid. Have you tried reinstalling the app?

warpling avatar Jan 21 '16 01:01 warpling

Yes , it works reinstalling the app, I figure out that the issues is on "appStoreReceiptURL", it seems to be cached or some thing like that. :S

NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSError *receiptError; BOOL isPresent = [receiptURL checkResourceIsReachableAndReturnError:&receiptError]; if (!isPresent) { // No receipt - In App Purchase was never initiated completionHandler(nil, nil); return; }

josueruiz7 avatar Jan 21 '16 01:01 josueruiz7

I've always had to delete the app to reset purchases. Even then, sometimes when I reinstall they quickly get restored if I forget to log out of the sandbox account.

warpling avatar Jan 21 '16 04:01 warpling

Hi @warpling I changed of library, I used the follow: https://github.com/robotmedia/RMStore RMStore seems better, use openssl. Regards

josueruiz7 avatar Jan 22 '16 16:01 josueruiz7

Ah neat! I'll look into using that.

warpling avatar Jan 22 '16 20:01 warpling