Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

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

Open
warpling opened this issue Dec 14, 2015 · 10 comments

Comments

@warpling
Copy link

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! :)

@josueruiz7
Copy link

Hello @warpling

Do you have the code to fix it?

Regards

@warpling
Copy link
Author

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 {

@josueruiz7
Copy link

it works perfect! Thank you!

@warpling
Copy link
Author

😊 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, josueruiz7notifications@github.com, wrote:

it works perfect! Thank you!


Reply to this email directly orview it on GitHub(#255 (comment)).

@josueruiz7
Copy link

@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.

@warpling
Copy link
Author

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

@josueruiz7
Copy link

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;
}

@warpling
Copy link
Author

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.

@josueruiz7
Copy link

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

@warpling
Copy link
Author

Ah neat! I'll look into using that.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants