3

One question about offline receipt verification using RMStore (https://github.com/robotmedia/RMStore)

On App start I check if the app has a valid in app purchase (PRO Version) (my App is iOS7 only)

I do that like that:

RMStoreAppReceiptVerificator *verificator = [[RMStoreAppReceiptVerificator alloc] init];
BOOL isValidReceipt = [verificator verifyAppReceipt];
if (isValidReceipt)
{
    BOOL isProVersion = [[RMAppReceipt bundleReceipt] containsInAppPurchaseOfProductIdentifier:xxx];
    ...
}

I still have version 1.0 in the App Store... But now i'd like to make an update soon... This will still work after an app store update, right? The App will still have the receipt in there and verification should still pass, right?

I ask because testing in-app purchases is not really easy (especially updating and stuff) and if something fails users would be pissed....

Georg
  • 3,664
  • 3
  • 34
  • 75

1 Answers1

4

The code should work as before. However, you're not verifying the receipt correctly. Quoting the Receipt Validation Programming Guide:

If validation fails in iOS, use the SKReceiptRefreshRequest class to refresh the receipt.

Using RMStore, that would look like this:

const BOOL verified = [self verifyReceiptWithCustomLogic];
if (verified)
{
    // Verification succeeded
} 
else 
{ // Apple recommends to refresh the receipt if validation fails on iOS
    [[RMStore defaultStore] refreshReceiptOnSuccess:^{
        const BOOL verified = [self verifyReceiptWithCustomLogic];
        if (verified)
        {
            // Verification succeeded
        }
        else
        {
            // Verification failed
        }
    } failure:^(NSError *error) {
            // Verification failed
    }];
}

Where your verification logic appears to be:

- (BOOL)verifyReceiptWithCustomLogic
{
    RMStoreAppReceiptVerificator *verificator = [RMStoreAppReceiptVerificator new];
    if ([verificator verifyAppReceipt])
    {
        return [[RMAppReceipt bundleReceipt] containsInAppPurchaseOfProductIdentifier:xxx];
    }
    return NO;
}

Note that refreshing the receipt makes receipt verification an asynchronous process.

neowinston
  • 7,584
  • 10
  • 52
  • 83
hpique
  • 119,096
  • 131
  • 338
  • 476
  • I'll add a note to the `RMStoreAppReceiptVerificator` code documentation to make this clear. – hpique May 21 '14 at 14:54
  • Great, thank you! Just one more question: when can receipt validation fail? Can i somehow force that to test it? So my update should work fine? – Georg May 21 '14 at 14:59
  • That is a different question, and it's completely independent from RMStore. I encourage you to ask it on StackOverflow as well. – hpique May 21 '14 at 15:09
  • I'd be careful with automatically refreshing the receipt on app start if verification fails. I've had Apple reject my app because of this. Now I only refresh the receipt when the user chooses to restore purchases. The linked Apple programming guide implies this should be ok, but my experience has been otherwise. – Edward Dale May 22 '14 at 05:31
  • 1
    @scompt.com I believe that refreshing the receipt prompts the user for their Apple password, which if you do it every time at startup, or even at first run, is bad user experience. In my experience, the receipt might fail to validate once, but once it passes, you shouldn't have to refresh it again. – hpique May 22 '14 at 06:06
  • @hpique why wouldn't there be a need to refresh again? Is the receipt cached by RMStore? Testing this out I am constantly getting all my in app purchases when I call `[RMAppReceipt bundleReceipt] inAppPurchases];` on startup even though I'm logged out of my App Store account. The only way the receipts are not returned is if I log in as a user that never purchased anything. – AdamT Oct 24 '15 at 05:52