Refreshing iOS app receipt: How to determine if user will need to sign in for app store?

Jason picture Jason · Nov 25, 2013 · Viewed 14.8k times · Source

I am implemeting Apple's "Grand unified receipt" on iOS 7, which allows the app to check an app's purchase receipt locally without having to contact Apple's servers for validation & verification. This works great if the user has a receipt stored in the app. Iin the case that the app is missing the receipt, the best practice is to request the app to refresh its receipt, as such:

    SKReceiptRefreshRequest *request = [[SKReceiptRefreshRequest alloc] init];
    [request setDelegate:self];
    [request start];

The issue is that calling this code will ask the user to log in with his or her Apple ID. I am not 100% sure if this happens all of the time, or only if the user's app store login has timed out. I don't want to display the Apple ID login screen to users unless it is really necessary - I don't want people to be concerned that they will be charged incorrectly. I would like to show a display telling the user why they will be asked for their Apple ID password, but only if they will actually be required to enter their password. If they don't need to enter their password I want it to be a seamless and hidden process. What's the best way to proceed? I think the best way would be to check if the user will need to sign in for the app store, but I'm not sure if that is possible.

Answer

Andy Ibanez picture Andy Ibanez · Jan 12, 2014

It is being very complicated to deal with this, so this answer may not be completely satisfactory (and I'm late - I'm aware of that), but still, hopefully this will help you a bit with this particular problem.

There's a chance I'm not doing this right either, but so far everything works and makes sense to me, but please if I'm "talking BS" here, feel free to correct me.

But anyway, you cannot really prevent the authentication alert from showing up, but there are a few ways you can minimize how many times it shows up.

You don't need to re-download a receipt that you know doesn't exist. If the user didn't buy or hasn't restored the receipt, you can avoid attempting to redownload a receipt and avoid the alert view altogether. This is something I have done:

if([[NSFileManager defaultManager] fileExistsAtPath:[[[NSBundle mainBundle] appStoreReceiptURL] path]] != YES)
{
    SKReceiptRefreshRequest *refresh = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
    [refresh start];
}

I put this on my main.m file, before the main application loop, as my app has many "pro" features that get unlocked with IAP, but you can really put this where you find it relevant.

The main idea is that the receipt is an actual file stored in your app's directory. So everything we are doing here is checking if the receipt actually exists. If it doesn't, we save us the trouble of re-freshing it and therefore saving the trouble of showing the auth screen to the user.

If you want, you can put this code anywhere where the user might use a "pro" feature of your app. SKReceiptRefreshRequest inherits from SKRequest and because of that it will call the SKRequestDelegate methods. So the moment a user navigates to a screen with a pro feature, you can refresh the receipt, and then enable the feature when the delegate methods get called (and after doing the extra work of checking the receipt's contents).

The big downside with this approach is that it does require an internet connection. If your app works offline, the user will expect all its IAPs to work offline as well, so redownloading the receipt will be a problem under certain scenarios.