正如in this question和其他地方所讨论的那样,Apple现在要求应用程序为用户提供一种方法来恢复In App Purchase的已完成交易。
我全力以赴。我的应用程序的第一个版本以某种方式让它在没有它的情况下进行了审核(当时我还没有意识到这个规则,和/或它还没有被强制执行),但后来我开始接收来自用户的大量电子邮件询问缺少的内容(也有数据存储指南,并且不会备份繁重的可下载内容)。
所以,假设我在我的UI中的某处包含了一个“恢复”按钮,当点击调用时:
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
到现在为止还挺好。将提示用户输入AppleID和/或密码,并开始恢复过程。
我遇到的问题是:如果没有要恢复的事务,在AppleID提示之后我的应用程序基本上没有任何反应,这可能会让用户感到困惑或使应用程序看起来没有响应或损坏。
我希望能够显示“所有购买都是最新的”或类似的警报视图。
我可以在我的Transaction Observer代码中做些什么来检测这种情况吗?
有没有人认为这将是一个糟糕的设计,UX明智?
您还可以实现以下委托函数:
-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
-(void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
然后,您将知道还原过程何时完成或失败。您可以在paymentQueueRestoreCompletedTransactionsFinished中混合使用queue.transactions.count来查看是否已恢复任何事务。
请记住处理SKPaymentTransactionStateRestored
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
您可能还希望以与使用SKPaymentTransactionStatePurchased事务相同的方式处理已恢复的事务。
这仍然是最新的SDK / xCode 8.0,Swift 3中的一个问题 - 如果未进行任何购买的用户尝试“恢复”,则使用以下方法:
SKPaymentQueue.default().restoreCompletedTransactions()
不会触发处理购买/恢复的常用委托方法:
paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {...}
有趣的是,也可能没有调用可能应该捕获错误的方法:
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error){...}
相反,触发了可选方法,就好像恢复工作正常:
func paymentQueueRestoreCompletedTransactionsFinished()
这可能会导致应用看起来像挂起/没做任何事情。
正如其他答案中所讨论的,原因是SKPaymentQueue不包含任何交易。
在Swift中,可以通过使用以下方法克服此问题:
//Optional Method.
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue)
{
let transactionCount = queue.transactions.count
if transactionCount == 0
{
print("No previous transactions found")
//You can add some method to update your UI, indicating this is the problem e.g. use notification centre:
NotificationCenter.default.post(name: "restoreFailedNoPrevIAP", object: nil)
}
}
重要的是,如果用户先前已购买,则事务队列将不为空,因此将调用updateTransaction委托方法,并将正常处理还原请求。
我对恢复购买的正确/最佳措辞感兴趣。
我已经看到足够的“未知错误”警报,只需在[error localizedDescription]
中使用-(void)paymentQueue:restoreCompletedTransactionsFailedWithError:
。 (todo:填充雷达)
所以我看看Apple如何做到这一点。 Apple现在购买非消费类应用程序的唯一应用程序是GarageBand(2014年12月)。
而不是“恢复购买”,“恢复以前的购买”或......他们使用"Already Purchased?"
。
但是这里是我更感兴趣的屏幕,当没有什么可以恢复时按下"Already Purchased?"
的结果:
"There are no items available to restore at this time."
不是革命性的,但打败了“未知的错误”
所以让我们来看看-(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:
我对OS X上的相同文本不满意。只有messageText和没有informativeText的NSAlert看起来空洞和错误。
对我来说,一个选择就是让用户知道他需要购买它,例如"To use it, you need to buy “%@”."
。
我想出的另一个选择是让他们浏览Purchase History。我发现你可以用itms://phobos.apple.com/purchaseHistory
直接链接到它。老实说,iTunes Store中的购买历史是一件糟糕的事情,它会让你永远找到一些东西。
但也许它有助于再保险人员,我们不会试图让他们重新购买一些东西。始终假设您的客户不知道或不能区分非消耗品和消耗品。并且不知道他们不能为非消耗品收取两次费用。
- (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];
}
}
OS X上的示例
测试说明(OS X,itunesconnect沙箱用户):
用户点击取消时:
- (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}
什么都没有恢复时:
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
Error Domain=SKErrorDomain Code=0 "Unknown Error." UserInfo=0x60800007fb80 {NSLocalizedDescription=Unknown Error.}
我在我正在处理的应用程序中遇到了同样的问题。我的解决方法是使用X秒计时器。它会在您点击“恢复购买”按钮时启动,并在恢复的事务事件进入时重新启动。一旦达到X秒标记,我会弹出一个“购买已恢复”的弹出窗口。因此,如果您没有交易,则只需等待X秒。希望有所帮助。