我正在尝试使用SKPaymentQueue.default()。restoreCompletedTransactions()恢复非消耗性IAP,但按照计划没有任何效果。在沙盒中,我收到“没有可用的应用内购买信息。请稍后再试。21105”,在Prod中,什么也没有发生。从我可以看到,实际的SKPaymentQueue.default()。restoreCompletedTransactions()行引发了沙箱中的错误,此后未进行任何处理。我确信一切都正确,因为我可以手工购买并且可以正常使用,所以我也可以再次购买任何有错误的东西,即我已经拥有它,然后激活该项目,但是“还原”按钮不起作用(restorePurchases()) 。我的应用程序中确实有38个IAP,但是我不确定这是否以任何方式关联,并且它们都是非消耗性的。出售贴纸的是iMessage Extension。另一个奇怪的是,Apple确实取消了我的应用程序,因为我在未经我自己许可的情况下使用了自己的Art(这很有趣),但是所有情况都表明,使用非消耗品必须具有Restore(还原)功能,Apple对此进行检查。情况一切都在不工作的情况下通过了。
我的IAP类别是:
import Foundation
import StoreKit
import os.log
class IAPService: NSObject
{
private override init() {} // make sure there is no extra copies
static let shared = IAPService() // makes this singleton
fileprivate var products = [SKProduct]()
let paymentQueue = SKPaymentQueue.default()
let defaults = UserDefaults.standard
var haveData = false
var reference = StickewrsCollectionViewController()
fileprivate var request = SKProductsRequest()
let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "IAPService")
let receiptFetcher = ReceiptFetcher()
func getProducts()
{
let allStickersIAP = “IAP reference”
var iapList = Dictionary<String, String>()
if let path = Bundle.main.path(forResource: "StickersData", ofType: ".plist")
{
let dict = NSDictionary(contentsOfFile: path) as! Dictionary<String, AnyObject>
let globalData = dict["StickerData"] as! Array<AnyObject>
iapList = (globalData[1]) as! Dictionary<String, String>
}
var products: Set = [allStickersIAP]
for iap in iapList
{
products.insert(iap.value)
}
request = SKProductsRequest(productIdentifiers: products)
request.delegate = self
request.start()
paymentQueue.add(self)
SKPaymentQueue.default().add(self)
os_log("Getting products")
}
func purchase(product: String)
{
if (SKPaymentQueue.canMakePayments())
{
guard let productToPurchase = products.filter({$0.productIdentifier == product}).first
else {return}
let payment = SKPayment(product: productToPurchase)
paymentQueue.add(payment)
}
}
func restorePurchases()
{
print("Restoring purchases")
os_log("Restoring purchases")
SKPaymentQueue.default().restoreCompletedTransactions()
}
func iapCheck() -> Bool
{
return SKPaymentQueue.canMakePayments() && haveData
}
func getProductData(iap: String) -> SKProduct
{
return products.filter({$0.productIdentifier == iap}).first ?? SKProduct()
}
func priceStringForProduct(item: SKProduct) -> String? {
let price = item.price
if price == NSDecimalNumber(decimal: 0.00) {
return NSLocalizedString("free", comment: "")
} else {
let numberFormatter = NumberFormatter()
let locale = item.priceLocale
numberFormatter.numberStyle = .currency
numberFormatter.locale = locale
return numberFormatter.string(from: price)
}
}
func setReference(ref: StickewrsCollectionViewController)
{
reference = ref
}
public func passPopUp(_ text: String)
{
reference.ShowPopUp(text)
}
// Called when the application is about to terminate.
func applicationWillTerminate(_ application: UIApplication) {
// Remove the observer.
SKPaymentQueue.default().remove(self)
}
}
extension IAPService: SKProductsRequestDelegate, SKPaymentTransactionObserver
{
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
products = response.products
haveData = true
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState
{
case .purchasing: break
case .purchased:
do {
defaults.set(true, forKey: transaction.payment.productIdentifier)
defaults.synchronize() // save changes in PlayerPrefs
print(transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
}
case .restored:
do {
print("Do actual restoring")
os_log("Now restoring %@", transaction.original!.payment.productIdentifier)
reference.ShowPopUp("Restoring purchase \(transaction.original!.payment.productIdentifier)")
defaults.set(true, forKey: transaction.original!.payment.productIdentifier)
defaults.synchronize() // save changews in PlayerPrefs
print(transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
}
default: queue.finishTransaction(transaction)
}
}
reference.redrawnAfterPurchase()
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
for transaction in queue.transactions {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
defaults.set(true, forKey: prodID)
defaults.synchronize() // save changews in PlayerPrefs
print(prodID)
queue.finishTransaction(transaction)
}
reference.redrawnAfterPurchase()
reference.ShowPopUp(NSLocalizedString("restoreCompleted", comment: ""))
}
}
extension SKPaymentTransactionState
{
func status() -> String
{
switch self {
case .deferred: return "deferred"
case .failed: return "failed"
case .purchased: return "purchased"
case .purchasing: return "purchasing"
case .restored: return "restored"
}
}
}
我做错了什么,如何使RestorePurchases实际执行某些操作?