Yuri Jose Yuri Jose - 13 days ago 11
iOS Question

(Swift) In-App Purchase - SKProductResquest is 0 (nil)

Good afternoon

Obs: I use the Rechiability class to check if the user internet is connected or not but in this case the class verify the internet but i dont receive the information from apple.
So I know this is giving unwrapping nil value because in the productRequest method the response.products is not receiving any product, however it is only in the case below.

I created a payment system and it works fine, however there is a case that it is crashing which is:

1 User enters app without internet connection (Wi-Fi or 4G).

2 User tries to buy the app offline and gets into the purchase viewcontroller.

3 Press the iphone HOME button and then connect the Wi-Fi or 4G.

4 After return to the app and press the button to purchase again and the crash appear.

This only happens in this situation, in the other test cases I did not receive any errors.

I can not see why this error occurred.

Below is my code and images about the error.

My current code:

import UIKit
import StoreKit

protocol IAPManagerDelegate
{
func managerDidRestorePurchases()
}

class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver, SKRequestDelegate
{

static let sharedInstance = IAPManager()

var request:SKProductsRequest!
var products:NSArray!

//Load product identifiers for store usage
func setupInAppPurchases()
{
self.validateProductIdentifiers(self.getProductIdentifiersFromMainBundle())

SKPaymentQueue.default().add(self)
}

//Get product identifiers
func getProductIdentifiersFromMainBundle() -> NSArray
{
var identifiers = NSArray()
if let url = Bundle.main.url(forResource: "iap_product_ids", withExtension: "plist")
{
identifiers = NSArray(contentsOf: url)!
}

return identifiers
}

//Retrieve product information
func validateProductIdentifiers(_ identifiers:NSArray)
{

if Reachability.isConnectedToNetwork() == true
{
print("Enter")
let productIdentifiers = NSSet(array: identifiers as [AnyObject])
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
self.request = productRequest
productRequest.delegate = self
productRequest.start()
}

}

func createPaymentRequestForProduct(_ product:SKProduct)
{

if Reachability.isConnectedToNetwork() == true
{
let payment = SKMutablePayment(product: product)
payment.quantity = 1
SKPaymentQueue.default().add(payment)
}
}


//MARK: SKProductsRequestDelegate
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse)
{
//
self.products = response.products as NSArray!

for product in products
{
let temp = product as! SKProduct

if temp.productIdentifier == "monthly.subscription"
{
print("price: \(temp.price)")
formatProductMonth(free: temp)
}
if temp.productIdentifier == "weekly.subscription"
{
print("price: \(temp.price)")
formatProductFree(free: temp)
}
if temp.productIdentifier == "yearly.subscription"
{
print("price: \(temp.price)")
formatProductYear(free: temp)
}
}
// print("Product[0]: \(string)")
// print("Product[1]: \(prod1.productIdentifier)")
// print("Product[2]: \(prod2.productIdentifier)")
}

//MARK: SKPaymentTransactionObserver Delegate Protocol
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])
{


//
for transaction in transactions as [SKPaymentTransaction]
{
switch transaction.transactionState
{
case .purchasing:
print("Purchasing")
UIApplication.shared.isNetworkActivityIndicatorVisible = true
break
case .deferred:
print("Deferrred")

let alertController: UIAlertController = UIAlertController(title: "Deferred", message: "Purchase deferred", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(dismiss)
alertController.show()
UIApplication.shared.isNetworkActivityIndicatorVisible = false
break
case .failed:
print("Failed")
//print(transaction.error?.localizedDescription)
UIApplication.shared.isNetworkActivityIndicatorVisible = false
SKPaymentQueue.default().finishTransaction(transaction)
let alertController: UIAlertController = UIAlertController(title: "Failed", message: "Purchase failed", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(dismiss)
alertController.show()
//UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
break
case.purchased:
StopActivator()
print("Purchased")
self.verifyReceipt(transaction)
let thankyou = UserDefaults.standard.bool(forKey: "Purchased")

if thankyou == true
{

let alertController: UIAlertController = UIAlertController(title: "Thank You", message: "Purchase completed", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: { (action: UIAlertAction!) in
UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true, completion: nil)
})
alertController.addAction(dismiss)
alertController.show()

}

break
case .restored:
print("Restored")
let alertController: UIAlertController = UIAlertController(title: "Restore Success", message: "Your purchases have been restored", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(dismiss)
alertController.show()
break

}
}
}


Pictures for the errors above:

First Image

Second Image

Please I know what is unwrapping an Optional Value "Obs: I use the Rechiability class to check if the user internet is connected or not but in this case the class verify the internet but i dont receive the information from apple. So I know this is giving unwrapping nil value because in the productRequest method the response.products is not receiving any product, however it is only in the case below."

My question is why is giving this error in this case: " I created a payment system and it works fine, however there is a case that it is crashing which is: 1 User enters app without internet connection (Wi-Fi or 4G). 2 User tries to buy the app offline and gets into the purchase viewcontroller. 3 Press the iphone HOME button and then connect the Wi-Fi or 4G. 4 After return to the app and press the button to purchase again and the crash appear."

Answer

The problem was in the apple servers, but i built a fix for this.

Thanks for me.