恢复购买:非消耗品

Restore Purchase : Non-Consumable

我已经完成了一个小应用程序,其中有一个非消耗品购买选项。它在 App Store 上。

产品购买正常。是我的恢复购买功能好像什么都没做。

我已经为恢复购买添加了这个代码@IBAction:

@IBAction func restorePurchases(sender: AnyObject) { 
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}

但是当我点击恢复购买按钮时没有任何反应。

我想我必须添加一个功能来检查恢复是否成功。我计划将代码修改为以下内容:

@IBAction func restorePurchases(sender: AnyObject) { 
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}

func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {

for transaction:AnyObject in transactions {
    if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
        switch trans.transactionState {
        case .Restored:
            SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
        var alert = UIAlertView(title: "Thank You", message: "Your purchase(s) were restored.", delegate: nil, cancelButtonTitle: "OK")
        alert.show()
            break;

        case .Failed:
            SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
        var alert = UIAlertView(title: "Sorry", message: "Your purchase(s) could not be restored.", delegate: nil, cancelButtonTitle: "OK")
        alert.show()
        break;

        default:
        break;
        }
    }
}    

这样做有用吗?

我已经了解了与影响恢复购买交易相关的每条线索,并且我的研究使我得出了上述结论。所以我不认为这是一个重复的问题,但也许可以阐明如何为面临类似情况的其他人成功恢复购买。

你的代码大部分看起来都很好,尽管有些部分似乎来自旧教程。您应该进行一些更改,其中之一是您需要再次调用 unlockProduct 函数。

这是我使用的代码 (Swift 3).

/// Updated transactions
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

    for transaction in transactions {
         switch transaction.transactionState {

        case .purchasing:
            // Transaction is being added to the server queue.

        case .purchased:
            // Transaction is in queue, user has been charged.  Client should complete the transaction.

            defer {
                queue.finishTransaction(transaction)
            }

            let productIdentifier = transaction.payment.productIdentifier

            unlockProduct(withIdentifier: productIdentifier)

        case .failed:
            // Transaction was cancelled or failed before being added to the server queue.

            defer {
                queue.finishTransaction(transaction)
            }

            let errorCode = (transaction.error as? SKError)?.code

            if errorCode == .paymentCancelled {
                print("Transaction failed - user cancelled payment")
            } else if errorCode == .paymentNotAllowed { // Will show alert automatically
               print("Transaction failed - payments are not allowed")
            } else {
                print("Transaction failed - other error")
                // Show alert with localised error description 
            }

        case .restored:
            // Transaction was restored from user's purchase history.  Client should complete the transaction.

            defer {
                queue.finishTransaction(transaction)
            }

            if let productIdentifier = transaction.original?.payment.productIdentifier {
                unlockProduct(withIdentifier: productIdentifier)
            }

        case .deferred:
            // The transaction is in the queue, but its final status is pending external action 
            // e.g family member approval (FamilySharing). 
            // DO NOT freeze up app. Treate as if transaction has not started yet.
        }
    }
}

比使用委托方法显示恢复警报

/// Restore finished
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
    guard queue.transactions.count != 0 else {
        // showAlert that nothing restored
        return
    }

    // show restore successful alert 
}

/// Restore failed
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: NSError) {

     /// handle the restore error if you need to. 
}

解锁产品只是一种方法我相信你也已经有了。

  func unlockProduct(withIdentifier productIdentifier: String) {
       switch productIdentifier {
         /// unlock product for correct ID
     }
  }

作为旁注,您应该移动此行

 SKPaymentQueue.default().add(self)

退出你的恢复和购买功能并将其放入 viewDidLoad。

Apple 建议您在您的应用程序启动后立即添加事务观察器,并且仅在您的应用程序关闭时将其移除。不幸的是,很多教程都没有正确地教你这一点。这样您就无法确定任何未完成的交易(例如由于网络错误)是否会始终正确恢复。

https://developer.apple.com/library/content/technotes/tn2387/_index.html

在我的实际项目中,我的 IAP 代码在单例中 class 所以我实际上会使用委托将 unlockProduct 方法转发到我的 class 来处理 gameData。我还可以确保在应用启动时添加了观察者。

希望对您有所帮助

我花了一些时间才弄清楚,但我的 StoreKit 没有更新交易和恢复购买的原因是因为我的应用方案中的配置设置损坏。当我将其设置为 None 时,它起作用了!

在 Xcode 中,我进入“编辑”>“方案”(image1) 单击 运行>“选项”选项卡并为 StoreKit 配置 (image2) 选择 None。我还使用了我的物理设备,并注销了我的个人 Apple 购买帐户(设置 > 您的 Name/Pic 在顶部 > 媒体和购买 > 注销)(图 3)。最后,这一步可能并不重要,但我在设备上的“设置”>“应用商店”菜单(图片 4 和图片 5)底部登录了我的测试沙箱帐户。这是我在 developer.apple.com 测试用户下设置的帐户。