Я пытаюсь восстановить непотребляемый IAP с помощью SKPaymentQueue.default (). RestoreCompletedTransactions () и ничего не работает в соответствии с планом.В песочнице я получаю «Нет информации для покупок в приложении. Повторите попытку позже. 21105», а в Prod просто ничего не происходит.Из того, что я вижу, ошибка в Sandbox генерируется с фактической строкой SKPaymentQueue.default (). RestoreCompletedTransactions (), и после этого ничего не обрабатывается.Я уверен, что все правильно, так как я могу сделать свою покупку вручную, и она работает, я также могу выкупить что-нибудь снова с ошибкой, что у меня уже есть, и затем элемент активируется, но кнопка Восстановить не работает (restorePurchases ()),У меня есть 38 IAP в этом приложении, но я не уверен, связано ли это каким-либо образом, и все они не расходуемые.Это расширение iMessage, которое продает наклейки.Что также странно, это то, что Apple действительно откинула мое приложение назад, потому что я использовал свое собственное искусство без моего собственного разрешения (это было весело), но все утверждают, что с Non-Consumable должна быть проверка 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 действительно что-то делать?