Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have a production-signed app getting receipts from test environment on iOS?

I have an app that was rejected with this message:

“When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code “Sandbox receipt used in production,” you should validate against the test environment instead.”

When I run the app from Xcode using a test account, the purchase works fine in the sandbox. I also tried testing an ad-hoc build and it works using the test account too. I’ve submitted other apps with in-app purchase that basically use the same exact code and they were approved.

I’m also not sure what “for your production server to always validate receipts” is talking about. The in-app purchase is done entirely within the app and doesn’t need to access my server for anything.

I have a class StoreObserver that implements SKPaymentTransactionObserver

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
           case SKPaymentTransactionStatePurchased:
                // this is where it goes when I test it
                break;
            case SKPaymentTransactionStateFailed:
                // somehow Apple review is getting here
                break;
            …
        }
    }
}

In the view controller to make the in-app purchase:

- (void)viewDidLoad {
    [super viewDidLoad];
    storeObserver = [[StoreObserver alloc] init];
    storeObserver.delegate = self;
    [[SKPaymentQueue defaultQueue] addTransactionObserver:storeObserver];
}

- (void) viewDidAppear:(BOOL)animated {
    SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:@“productid”,nil]];
    request.delegate = self;
    [request start];
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    product = [response.products objectAtIndex:0]; 
    // show button for in-app purchase
}

// handle button click to make in-app purchase
- (IBAction) purchaseClick:(id)sender {
    [SKPayment *payment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

What do I need to do to make this work?

like image 484
Tom Kincaid Avatar asked Dec 12 '17 20:12

Tom Kincaid


1 Answers

You should be validating the receipt you get for the transaction. The recommended way of doing that is to upload the receipt to your server, then do server-to-server validation from there. This allows you to avoid certain types of hacks that can trick your app into believing a valid purchase has been made.

Details are here: Validating App Store Receipts

Apple is telling you what the guidelines above tell you. Submit the receipt to the production server first. If that fails with a 21007 error, you need to submit the receipt to the sandbox server.

like image 193
Craig Avatar answered Nov 20 '22 01:11

Craig