I was interested in the right/best wording for restoring purchase.
I have seen enough "Unknown Error" alerts, just using [error localizedDescription]
inside -(void)paymentQueue:restoreCompletedTransactionsFailedWithError:
. (todo: fill radar)
So I took a look at how Apple does it. The only app from Apple with Non-Consumable In-App Purchases right now is GarageBand (Dec, 2014).
Instead of "Restore Purchase", "Restore Previous Purchases" or ... they go with "Already Purchased?"
.
But here is the screen I'm more interested in, the result of pressing "Already Purchased?"
when there is nothing to restore:

"There are no items available to restore at this time."
Not revolutionary, but beats the hell out of "Unknown Error"
So lets look at -(void)paymentQueue:restoreCompletedTransactionsFailedWithError:
.
iOS:
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
if ([error.domain isEqual:SKErrorDomain] && error.code == SKErrorPaymentCancelled)
{
return;
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"There are no items available to restore at this time.", @"")
message:nil
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK", @"")
otherButtonTitles:nil];
[alert show];
}
OS X:
I'm not happy with just the same text on OS X. An NSAlert with just the messageText and no informativeText just looks empty and wrong.
One option for me is to let the user know that he needs to purchase it, with something like "To use it, you need to buy “%@”."
.
Another option I came up with is letting them browser there Purchase History. I found that you can directly link to it with itms://phobos.apple.com/purchaseHistory
. In all honesty Purchase History in the iTunes Store is a piece of shit, it gonna take you for ever do find something.
But maybe it helps reinsuring people that we don't try to make them repurchase something. Always assume that your customers don't know or can't tell the difference between Non-Consumable and Consumable. And don't know that they can't get charged twice for a Non-Consumable.
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
if ([error.domain isEqual:SKErrorDomain] && error.code == SKErrorPaymentCancelled)
{
return;
}
NSAlert *alert = nil;
alert = [NSAlert alertWithMessageText:NSLocalizedString(@"There are no items available to restore at this time.", @"")
defaultButton:NSLocalizedString(@"OK", @"")
alternateButton:NSLocalizedString(@"Purchase History", @"")
otherButton:nil
informativeTextWithFormat:@"You can see your purchase history in the iTunes Store."];
NSModalResponse returnCode = [alert runModal];
if (returnCode == NSAlertAlternateReturn)
{
NSURL *purchaseHistory = [NSURL URLWithString:@"itms://phobos.apple.com/purchaseHistory"];
[[NSWorkspace sharedWorkspace] openURL:purchaseHistory];
}
}
Example on OS X

Testing Notes (OS X, itunesconnect sandbox user):
When user clicks cancel:
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
Error Domain=SKErrorDomain Code=2 "The payment was canceled by the user" UserInfo=0x600000470a40 {NSLocalizedDescription=The payment was canceled by the user}
When there is nothing to restore:
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
Error Domain=SKErrorDomain Code=0 "Unknown Error." UserInfo=0x60800007fb80 {NSLocalizedDescription=Unknown Error.}