SwiftyStoreKit.purchaseProduct - Закрытие в делегате приложения не вызывается

В моем Podfile я использую SwiftyStoreKit (0.15.0):

pod 'SwiftyStoreKit'

В моем приложении используется банку с советами для IAP, поэтому я использую только Consumable.

Я отправил свое приложение в App Store сегодня утром и получил отказ, в котором говорилось, что они не могут сделать IAP при попытке сделать Consumable покупку (совет).

Во время тестирования в качестве тестера песочницы, когда я проверял покупку, я постоянно получал ошибку: "Unknown error. Please contact support":

SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in

    switch result {
        case .success(let product):
            // fetch content from your server, then:
            if product.needsFinishTransaction {

                SwiftyStoreKit.finishTransaction(product.transaction)
            }
            print("Purchase Success: \(product.productId)")

        case .error(let error):
             switch error.code {
                case .unknown:
                     print("Unknown error. Please contact support")
        // failed cases ...
    }
}

При дальнейшей проверке, хотя у меня был этот код ниже в AppDelegate, closure никогда не вызывается. Это необходимо, этот код запускается один раз в AppDelegate

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    // Doesn't enter closure
    SwiftyStoreKit.completeTransactions(atomically: true) { 

        // *** it never reaches this point ***

        (purchases) in

        for purchase in purchases {
            switch purchase.transaction.transactionState {
            case .purchased, .restored:
                if purchase.needsFinishTransaction {
                    // Deliver content from server, then:

                    let downloads = purchase.transaction.downloads
                    SKPaymentQueue.default().start(downloads)

                    SwiftyStoreKit.finishTransaction(purchase.transaction)
                }
                // Unlock content
            case .failed, .purchasing, .deferred:
                break // do nothing
            }
        }
    }
    return true
}

Мой адрес электронной почты тестировщика песочницы подтвержден, я вышел из устройства как настоящий я, я вошел в систему на устройстве как тестер песочницы, я вошел в iCloud как тестер песочницы.

По какой причине замыкание не вводится в AppDelegate?

Вот код из vc, который я использую для покупки Consumable:

var dataSource = [Tip]()
var sharedSecret = appStoreConnectSecretKey

let inAppProductIds = ["com.myCo.myAppName.firstTip", // 0.99
                       "com.myCo.myAppName.secondTip", // 9.99 ]

override func viewDidLoad() {
    super.viewDidLoad()

   getInAppPurchaseAmounts()
}

func getInAppPurchaseAmounts() {

    // show spinner

    let dispatchGroup = DispatchGroup()

    for productId in inAppProductIds {

        dispatchGroup.enter()

        SwiftyStoreKit.retrieveProductsInfo([productId]) { [weak self](result) in
            if let product = result.retrievedProducts.first {
                let priceString = product.localizedPrice!
                print("Product: \(product.localizedDescription), price: \(priceString)")

                let tip = Tip(displayName: product.description,
                              description: product.localizedDescription,
                              productId: productId
                              price: priceString)


                self?.addTipToDataSource(tip)

                if let sharedSecret = self?.sharedSecret {

                    self?.verifyPurchase(with: productId, sharedSecret: sharedSecret)
                }
                dispatchGroup.leave()

            } else if let invalidProductId = result.invalidProductIDs.first {
                print("Invalid product identifier: \(invalidProductId)")
                dispatchGroup.leave()

            } else {
                print("Error: \(String(describing: result.error))")
                dispatchGroup.leave()
            }
        }
    }

    dispatchGroup.notify(queue: .global(qos: .background)) { [weak self] in
        DispatchQueue.main.async { [weak self] in

            // removeSpinnerAndReloadData()
        }
    }
}

func verifyPurchase(with productId: String, sharedSecret: String) {

    let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: sharedSecret)
    SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
        switch result {
        case .success(let receipt):
            let productId = productId
            // Verify the purchase of Consumable or NonConsumable
            let purchaseResult = SwiftyStoreKit.verifyPurchase(
                productId: productId,
                inReceipt: receipt)

            switch purchaseResult {
            case .purchased(let receiptItem):
                print("\(productId) is purchased: \(receiptItem)")
            case .notPurchased:
                print("The user has never purchased \(productId)")
            }
        case .error(let error):
            print("Receipt verification failed: \(error)")
        }
    }
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath) as? TipCell else { return }
    guard let indexPath = collectionView.indexPath(for: cell) else { return }

    let tip = dataSource[indexPath.item]

    purchaseProduct(with: tip.productId)
}

func purchaseProduct(with productId: String) {

    SwiftyStoreKit.retrieveProductsInfo([productId]) { result in
        if let product = result.retrievedProducts.first {
            SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in

                switch result {
                case .success(let product):
                    // fetch content from your server, then:
                    if product.needsFinishTransaction {
                        SwiftyStoreKit.finishTransaction(product.transaction)
                    }
                    print("Purchase Success: \(product.productId)")
                case .error(let error):
                    switch error.code {
                    case .unknown:
                        print("Unknown error. Please contact support")
                    case .clientInvalid:
                        print("Not allowed to make the payment")
                    case .paymentCancelled:
                        print("Payment cancelled")
                    case .paymentInvalid:
                        print("The purchase identifier was invalid")
                    case .paymentNotAllowed:
                        print("The device is not allowed to make the payment")
                    case .storeProductNotAvailable:
                        print("The product is not available in the current storefront")
                    case .cloudServicePermissionDenied:
                        print("Access to cloud service information is not allowed")
                    case .cloudServiceNetworkConnectionFailed:
                        print("Could not connect to the network")
                    case .cloudServiceRevoked:
                        print("User has revoked permission to use this cloud service")
                    default:
                        print((error as NSError).localizedDescription)
                    }
                }
            }
        }
    }
}

person Lance Samaria    schedule 02.11.2019    source источник
comment
У меня такая же проблема, кто-нибудь решил это? Я использую Xcode 11.5 and swift 5. Также используется SwiftyStoreKit последняя версия 0.15.0   -  person Zubair Ahmed    schedule 24.06.2020
comment
@ZubairAhmed это не замыкание, этот код работает нормально даже без замыкания. У меня есть 2 приложения в AppStore, использующие точно такой же код. Я все еще хотел бы знать, почему происходит закрытие, но вам следует задать еще один вопрос, добавить свой код и подробно описать, что вы сделали, чтобы зарегистрироваться. Я прошел через возгласы и препятствия, и мне пришлось связаться с Apple, чтобы выяснить проблему. Пожалуйста, свяжите свой вопрос здесь, когда закончите, чтобы я (или кто-то другой) мог попытаться вам помочь. У меня такое чувство, что ты совершил ту же ошибку, что и я.   -  person Lance Samaria    schedule 25.06.2020
comment
Привет Лэнс. Не могли бы вы поделиться своей ошибкой вместо того, чтобы оставить ее открытой?   -  person Lukas Bimba    schedule 03.05.2021
comment
@LukasBimba привет, это было так давно, что я точно не помню. Я должен все обдумать, дай мне секунду. Вопрос, вам отказали или вы столкнулись с этим вопросом, беспокоясь о том, что вас отвергнут?   -  person Lance Samaria    schedule 03.05.2021
comment
@LukasBimba Если я правильно помню, мне нужно было убедиться, что я использую правильный адрес электронной почты Sandbox Tester. На вашем iPhone перейдите по адресу: Settings > Your Username (AppleID, iCloud, iTunes & App Store) > iTunes & App Store > SANDBOX ACCOUNT — этот Apple ID должен быть тем, что вы создали в AppStoreConnect для электронной почты песочницы. Убедитесь, что вы входите в свой iPhone и iCloud как один и тот же тестер песочницы для любого тестера песочницы электронной почты APP ID, который вы создали в AppStoreConnect. Опять же, это расплывчато, но я считаю, что именно так я заставил все работать правильно.   -  person Lance Samaria    schedule 03.05.2021