20

正如在这个问题和其他地方所讨论的那样,Apple 现在要求应用程序包含一种方法,供用户恢复已完成的应用内购买交易。

我完全赞成这个。我的应用程序的第一个版本在没有它的情况下通过了审查(当时我不知道这条规则,和/或它还没有被强制执行),但后来我开始收到很多来自用户的电子邮件询问丢失的内容(也有数据存储指南,并且没有备份大量可下载的内容)。

因此,假设我在 UI 中的某处包含一个“恢复”按钮,当点击该按钮时:

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

到现在为止还挺好。系统会提示用户他的 AppleID 和/或密码,然后恢复过程开始。

我遇到的问题是:如果没有要恢复的事务,则在 AppleID 提示之后,我的应用程序中基本上没有任何反应,这可能会使用户感到困惑或使应用程序看起来无响应或损坏。

我希望能够显示“所有购买都是最新的”或其他内容的警报视图。

我可以在我的 Transaction Observer 代码中做些什么来检测这种情况吗?

有没有人认为这将是一个糟糕的设计,UX 方面?

4

4 回答 4

11

这在最新的 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 委托方法,并正常处理恢复请求。

于 2016-09-26T13:29:39.183 回答
10

您还可以实现以下委托函数:

-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
-(void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error

然后您会知道恢复过程何时完成或是否失败。您可以在 paymentQueueRestoreCompletedTransactionsFinished 中混合使用 queue.transactions.count 以查看是否恢复了任何交易。

记得在 SKPaymentTransactionStateRestored 中处理

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

您可能还希望以与 SKPaymentTransactionStatePurchased 交易相同的方式处理恢复的交易。

于 2012-08-10T21:35:42.317 回答
9

我对恢复购买的正确/最佳措辞感兴趣。

我已经看到了足够多的“未知错误”警报,只是使用[error localizedDescription]inside -(void)paymentQueue:restoreCompletedTransactionsFailedWithError:。(待办事项:填充雷达)

所以我看了一下Apple是如何做到的。Apple 目前唯一具有非消耗性应用内购买的应用是 GarageBand(2014 年 12 月)。

而不是“恢复购买”,“恢复以前的购买”或......他们去"Already Purchased?"

购买画面 1

但是这里是我比较感兴趣的画面, "Already Purchased?"没有什么可以恢复的时候按下的结果:

购买画面 2

"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 上的相同文本不满意。只有 messageText 而没有 informationativeText 的 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 上的示例

测试笔记(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.}
于 2014-12-05T23:25:02.683 回答
0

我在我现在正在开发的应用程序中遇到了同样的问题。我的解决方法是使用 X 秒计时器。当您点击“恢复购买”按钮时它开始,如果恢复的交易事件进入,它会重新启动。一旦它达到 X 秒标记,我会弹出一个显示“已恢复购买”的弹出窗口。因此,如果您没有交易,您应该只需要等待 X 秒。希望有帮助。

于 2012-07-26T07:40:52.283 回答