Не срабатывает покупка только при первом запуске
В моем приложении есть встроенная покупка. Моя покупка активируется после нажатия кнопки. Но если я открываю приложение в первый раз и нажимаю кнопку, я получаю следующий результат: No products found with identifier
из этой функции:
func purchaseProduct(identifier:String) {
guard let product = self.product(identifier: identifier) else {
print("No products found with identifier: \(identifier)")
// fire purchase status: failed notification
delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .failed, error: PurchaseError.productNotFound, transaction: nil, message:"An error occured"))
return
}
//.etc
}
Но если после этого снова нажать кнопку, все работает нормально. Также, если я закрою приложение, снова открою его и нажму кнопку, покупка будет работать нормально. Почему это происходит только при первом запуске приложения? И как это исправить?
Есть следующий класс и думаю дело в нем:
class MyAppProductStore: Store {
static let shared = MyAppProductStore()
// purchase processor
var itunes: iTunesStore = iTunesStore()
init() {
// register for purchase status update callbacks
itunes.delegate = self
validateProducts(MyProductIds.allIdentifiers())
}
/// This function is called during the purchase/restore purchase process with each status change in the flow. If the status is complete then access to the product should be granted at this point.
///
/// - Parameter status: The current status of the transaction.
internal func processPurchaseStatus(_ status: PurchaseStatus) {
switch status.state {
case .initiated:
// TODO: show alert that purchase is in progress...
break
case .complete:
if let productID = status.transaction?.payment.productIdentifier {
// Store product id in UserDefaults or some other method of tracking purchases
UserDefaults.standard.set(true , forKey: productID)
UserDefaults.standard.synchronize()
}
case .cancelled:
break
case .failed:
// TODO: notify user with alert...
break
}
}
}
extension MyAppProductStore: iTunesPurchaseStatusReceiver, iTunesProductStatusReceiver {
func purchaseStatusDidUpdate(_ status: PurchaseStatus) {
// process based on received status
processPurchaseStatus(status)
}
func restoreStatusDidUpdate(_ status: PurchaseStatus) {
// pass this into the same flow as purchasing for unlocking products
processPurchaseStatus(status)
}
func didValidateProducts(_ products: [SKProduct]) {
print("Product identifier validation complete with products: \(products)")
// TODO: if you have a local representation of your products you could
// sync them up with the itc version here
}
func didReceiveInvalidProductIdentifiers(_ identifiers: [String]) {
// TODO: filter out invalid products? maybe... by default isActive is false
}
}
если после его вызова нажать на кнопку - все работать будет нормально.
Чтобы его вызвать использую следующую строку var store = MyAppProductStore() Я поместил ее в AppDelegate это выглядит так:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var store = MyAppProductStore()
.etc
Это самый быстрый способ вызвать?
No products found with identifier:
class iTunesStore: NSObject, SKProductsRequestDelegate {
weak var delegate: (iTunesProductStatusReceiver & iTunesPurchaseStatusReceiver)?
var transactionObserver: IAPObserver = IAPObserver()
var availableProducts: [SKProduct] = []
var invalidProductIDs: [String] = []
deinit {
SKPaymentQueue.default().remove(self.transactionObserver)
}
override init() {
super.init()
transactionObserver.delegate = self
}
func fetchStoreProducts(identifiers:Set<String>) {
print("Sending products request to ITC")
let request:SKProductsRequest = SKProductsRequest.init(productIdentifiers: identifiers)
request.delegate = self
request.start()
}
func purchaseProduct(identifier:String) {
guard let product = self.product(identifier: identifier) else {
print("No products found with identifier: \(identifier)")
//HUD.flash(.labeledError(title: "Попробуйте снова", subtitle: "Ошибка"), delay: 2.0)
// fire purchase status: failed notification
delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .failed, error: PurchaseError.productNotFound, transaction: nil, message:"An error occured"))
return
}
guard SKPaymentQueue.canMakePayments() else {
print("Unable to make purchases...")
delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .failed, error: PurchaseError.unableToPurchase, transaction: nil, message:"An error occured"))
return
}
// Fire purchase began notification
delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .initiated, error: nil, transaction: nil, message:"Processing Purchase"))
let payment = SKPayment.init(product: product)
SKPaymentQueue.default().add(payment)
}
func restorePurchases() {
// Fire purchase began notification
delegate?.restoreStatusDidUpdate(PurchaseStatus.init(state: .initiated, error: nil, transaction: nil, message:"Restoring Purchases"))
SKPaymentQueue.default().restoreCompletedTransactions()
}
// returns a product for a given identifier if it exists in our available products array
func product(identifier:String) -> SKProduct? {
for product in availableProducts {
if product.productIdentifier == identifier {
return product
}
}
return nil
}
}
// Receives purchase status notifications and forwards them to this classes delegate
extension iTunesStore: iTunesPurchaseStatusReceiver {
func purchaseStatusDidUpdate(_ status: PurchaseStatus) {
delegate?.purchaseStatusDidUpdate(status)
}
func restoreStatusDidUpdate(_ status: PurchaseStatus) {
delegate?.restoreStatusDidUpdate(status)
}
}
// MARK: SKProductsRequest Delegate Methods
extension iTunesStore {
@objc(productsRequest:didReceiveResponse:) func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
// set new products
availableProducts = response.products
// set invalid product id's
invalidProductIDs = response.invalidProductIdentifiers
if invalidProductIDs.isEmpty == false {
// call delegate if we received any invalid identifiers
delegate?.didReceiveInvalidProductIdentifiers(invalidProductIDs)
}
print("iTunes Store: Invalid product IDs: \(response.invalidProductIdentifiers)")
// call delegate with available products.
delegate?.didValidateProducts(availableProducts)
}
}