Hello I am having getting my App published on the App Store as they keep insisting my in-app purchases are not set up correctly.
Upon testing them myself in the sandbox, everything worked correctly.
This is the message they sent me, I pasted my code below.
Thank you for taking the time to help me out!
Guideline 2.1 - Performance - App Completeness
We found that your in-app purchase products exhibited one or more bugs when reviewed on iPhone and iPad running iOS 12 on Wi-Fi.
Specifically, your in app purchase buttons do not work.
Next Steps
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code “Sandbox receipt used in production,” you should validate against the test environment instead.
class IAPService: NSObject {
private override init() {}
static let shared = IAPService()
var products = [SKProduct]()
let paymentQueue = SKPaymentQueue.default()
func getProducts() {
let products: Set = [IAPProduct.consumable.rawValue,
IAPProduct.nonConsumable.rawValue]
let request = SKProductsRequest(productIdentifiers: products)
request.delegate = self
request.start()
paymentQueue.add(self)
}
func purchase(product: IAPProduct) {
for p in products {
if p.productIdentifier == product.rawValue {
let payment = SKPayment(product: p)
paymentQueue.add(payment)
print("Adding product to payment queue")
}
}
}
func restorePurchase() {
print("Restoring purchases")
paymentQueue.restoreCompletedTransactions()
}
func givePurchasedProduct(productID: String) {
if productID.range(of: "Zap") != nil {
NotificationCenter.default.post(name: Notification.Name.init("zapPurchased"), object: nil)
} else if productID.range(of: "Ads") != nil {
NotificationCenter.default.post(name: Notification.Name.init("noAdsPurchased"), object: nil)
}
}
}
extension IAPService: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
self.products = response.products
for product in response.products {
print(product.localizedTitle)
}
}
}
extension IAPService: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
print(transaction.transactionState.status(), transaction.payment.productIdentifier)
switch transaction.transactionState {
case .purchasing, .deferred: break // do nothing
case .purchased:
queue.finishTransaction(transaction)
givePurchasedProduct(productID: transaction.payment.productIdentifier)
case .restored:
self.restorePurchase()
queue.finishTransaction(transaction)
case .failed:
queue.finishTransaction(transaction)
}
}
}
}
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"
}
}
}