【问题标题】:iOS StoreKit - When to call - (void)restoreCompletedTransactions?iOS StoreKit - 何时调用 - (void)restoreCompletedTransactions?
【发布时间】:2013-04-18 13:28:56
【问题描述】:

我的应用程序中有很多 1 次购买 IAP。用户可以很好地购买它们。

我的问题是我正在与 Flurry 集成以跟踪实际购买而不是仅恢复购买,但我的 SKPaymentTransactiontransactionState 总是以 SKPaymentTransactionStatePurchased 而不是 SKPaymentTransactionStateRestored 返回。

显然SKPaymentTransactionStateRestored 只在- (void)restoreCompletedTransactions 时被调用,但是我什么时候调用这个方法呢?

我的想法是购买应该是这样的:1)用户选择产品,2)询问用户是否愿意以 X 金额购买产品。 3)服务器检查用户之前是否购买过,是否通过设置SKPaymentTransactionStateRestored恢复。否则,处理事务并设置SKPaymentTransactionStatePurchased。显然这是错误的,我想在两者之间打电话给- (void)restoreCompletedTransactions???

谢谢,

【问题讨论】:

  • 你应该看看stackoverflow.com/questions/1757467/…。就我而言,我将它与“恢复以前的交易”按钮一起使用
  • 感谢 Micazeve,但从分析的角度来看,听起来用户可以跳过按“恢复”按钮并通过尝试重新购买来恢复,因此继续跳过我分析用户是否购买的地方.也许当他们选择产品时,而不是立即开始交易,我可以做一个很可能是漫长而复杂的调用 restoreCompletedTransactions 的过程,查看所选产品是否在该列表中,如果不在,则 - 然后 - 让用户购买它.好痛……
  • 你说得对,这个按钮不是必需的,因为尝试重新购买已经购买的物品会警告用户他已经购买了该物品。这种情况下的主要问题是用户在接受再次付款后被警告:“恢复按钮”因此在心理方面很有用,因为用户不必再次进行付款程序。 -- 你可以尝试实现你的方法(应该可行),但正如你所说,这样的痛苦;)

标签: ios objective-c storekit


【解决方案1】:

编辑:

最初我发布了一个很长的、不需要的方法来完成我需要完成的工作,但正如您将在下面看到的那样,Matt 帮助我找出了我正在寻找的变量。

例如,假设用户之前购买了我的应用,购买了所有可用的非消耗性 IAP,然后删除了该应用。当用户重新安装应用程序时,我希望能够确定他们何时再次“购买”产品,是原始(第一次)购买,还是恢复购买?

我已经实现了一个“恢复所有购买”按钮,但假设用户忽略/没有看到它,并尝试选择他们之前购买的产品。

与正常购买一样,我会执行以下操作:

if ([SKPaymentQueue canMakePayments])
{
      self.productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:productID]];

      self.productRequest.delegate = self;
      [self.productRequest start];
}
else
{
     //error message here
}

用户登录他们的 iTunes 帐户后,该应用程序会通知他们他们已经购买了该产品,现在该产品将被恢复。将调用以下委托方法:

 -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{   
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
            {
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                if(transaction.originalTransaction)
                {
                    NSLog(@"Just restoring the transaction");
                }
                else
                {
                    NSLog(@"First time transaction");
                }

                break;
            }
            default:
                break;
        }
    }
}

无论交易是恢复还是首次购买,transaction.transactionState 将等于SKPaymentTransactionStatePurchased

现在从这一点来看,我们如何确定该购买是原始购买还是修复购买?

简单:如上所示,只看transaction.originalTransaction 是否被初始化。根据 Apple 的说明:// 仅当状态为 SKPaymentTransactionStateRestored 时才有效。

如果SKPaymentTransactionoriginalTransaction 被初始化,这意味着之前有一个事务。否则,本次交易为原创!

再次感谢 Matt 为我指明了正确的方向,并使逻辑更加清晰!

【讨论】:

  • “如果他们“重新购买”任何东西,我无法区分是原始购买还是修复购买”您不需要区分。商店将为您区分它。您排队购买,如果该用户已经进行了此购买,商店将提供它,而不会向用户收取第二次付款。
  • Matt,我知道它不会向用户收取两次费用,但用于记录购买(在我的实例中,通过 Flurry 记录事件,但这也可用于将数据存储在数据库中) ,我需要区分原始购买和修复。
  • 我还是不同意。让商店做商店做的事。让用户浏览商店的对话框(“您已经购买了这个,要重新下载吗?”)。如果是还原,那么当通知您的事务观察者时,该事务将具有originalTransaction 值,并且有您的差异(以及所有原始数据)。
  • 马特,我找到了你提到的变量,你是对的,我想要寻找。我将更新我的答案以反映这样做的最佳方式。谢谢!
【解决方案2】:

规范的期望似乎是您提供一个调用restoreCompletedTransactions 的恢复按钮。至于如果用户忽略了这一点,只是继续尝试通过您的购买界面来带回他已经购买的功能会发生什么,您可能会不必要地担心自己; docs 说:

如果用户尝试购买可恢复的产品(而不是使用您实现的恢复接口),应用程序会收到该项目的常规交易,而不是恢复交易。但是,用户不会再次为该产品付费。您的应用程序应将这些交易视为与原始交易相同的交易。

商店将弹出与用户交互的对话框(“您已经购买了这个,要再次免费下载吗?”),并且免费重新购买的通知将在您的@987654323 中进行@像往常一样,您可以使用它的originalTransaction.transactionIdentifier来识别它与原始购买。

【讨论】:

  • 好吧,我在你的 cmets 之后更新了我的答案,但如果只是这部分你推断“没有恢复按钮应该没问题”,我认为这还不够。
  • @guenis 这就是我想要找出的。苹果要求什么?他们坚持要一个实际的按钮吗?一方面你认为这没有必要,但另一方面他们确实说“你必须包含一个允许用户恢复这些购买的界面”。所以听起来你确实需要一个按钮。所以我的意思是,好吧,但是如果用户忽略了恢复按钮并只是尝试再次购买,你不必担心:它会起作用,并且不会向用户收取两次费用。
  • 修改了我的答案以解释如何判断“购买”何时实际上是免费重新下载(当用户“购买”他已经拥有的东西时)。
【解决方案3】:

如果您正在实施应用内购买,您需要在应用中的某处放置一个恢复按钮,否则这是一个拒绝原因。您可以查看Get list of purchased products, inApp Purchase iPhone 的一次事件。

编辑 2:除了放置一个按钮来避免拒绝之外,可能还有其他方法。 cmets 中建议的一种 matt 方法是在应用启动时恢复,这对我来说似乎足以符合苹果的指导方针。

还可以查看本教程的最后一部分,它提到了同样的问题,并展示了一种简单的实现方法: http://www.raywenderlich.com/21081/introduction-to-in-app-purchases-in-ios-6-tutorial

编辑:

//Draft implementation of transaction observer delegate

-(void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction * transaction in transactions) {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:                
                ...
            case SKPaymentTransactionStateFailed:
                ...
            case SKPaymentTransactionStateRestored:
                ...
            default:
                break;
        }
    };
}

【讨论】:

  • 这是真的吗?文档暗示您可以完全跳过该按钮。例如,您可以在启动时进行恢复。而且即使没有恢复,用户也可以再次购买,不会再次收费,那么商店为什么要关心没有恢复按钮呢?
  • 我完全同意你的看法。我写的是我在这里和那里读到的东西的总结,我还没有提交一个应用程序内支持的应用程序。启动时恢复似乎是最合理的解决方案,坦率地说,这是我在写答案时没有想到的。我会根据你所说的更新我的答案,谢谢。
  • 您无法在启动时进行还原,而不会在用户每次启动时都通过密码请求来烦扰用户。按钮周围没有实用的方法
【解决方案4】:

Apple IOS SDK 文档实际上在这个问题上具有误导性,因为它说:

@property(nonatomic, readonly) SKPaymentTransaction *originalTransaction
The contents of this property are undefined except when transactionState is set to SKPaymentTransactionStateRestored.

问题是当用户点击你的购买按钮,完成购买过程,最后得到一个他已经付款并且他可以免费重新下载的消息时,你的观察者并没有给你发送一个 SKPaymentTransactionStateRestored。它实际上向您发送了一个 SKPaymentTransactionStatePurchased。

好消息是,尽管有文档,但即使您的交易状态为 SKPaymentTransactionStatePurchased,您实际上也会获得属性 originalTransaction。只需测试该属性是否为零,您就会知道该交易是新购买的还是旧购买的免费恢复。

【讨论】:

    【解决方案5】:

    据我观察,有两种可能的情况,用户可能不得不调用恢复购买,

    1. 如果您不在后端服务器中维护购买信息:如果用户卸载应用程序或任何此类应用程序数据丢失的情况,您可能会丢失购买信息。在这种情况下,用户可以调用 restore,Storekit 将再次提供购买收据,您可以通过该收据确定用户是否之前购买过,以及该购买现在是否有效。

    2. 如果您将购买信息存储在您的支持中(支持的 api 决定用户是否有权订阅功能):可能存在您能够从 Apple 购买但不知何故无法更新到您的服务器的情况,在这种情况下,用户可以恢复购买,这将在您的后端服务器上更新购买信息,此后用户可以跨多个设备/平台/重新安装使用应用程序,但仍然有权获得特权访问。

    因此,始终建议在购买时在同一页面中显示恢复选项。 如果用户在未选择恢复的情况下在订阅有效的情况下无意中尝试购买, 1.如果他选择了与当前活跃onr相同的计划,他将被告知现有和订阅 2.如果他选择了当前订阅之外的其他计划,他/她将被告知当前订阅以及根据最新选择的计划升级/降级的选项。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多