I am developing an IOS app with in app purchases. While debugging via USB, the in app purchase shows up on all devices and I am able to purchase it. When deployed to TestFlight and installed, the in app purchase shows up on iPhones, but not on iPads. The UI element just doesn't load in that specific scenario. The in app purchase is set up within App Store Connect, and as I mentioned is loading properly when viewed on an iPhone.
Code for the view displaying the IAP:
List(storeManager.myProducts, id: \.self) { product in
HStack {
VStack(alignment: .leading) {
Text(product.localizedTitle)
.font(.headline)
Text(product.localizedDescription)
.font(.caption2)
}
Spacer()
if UserDefaults.standard.bool(forKey: product.productIdentifier) {
Text("Purchased")
.foregroundColor(.green)
} else {
Button(action: {
storeManager.purchaseProduct(product: product)
}) {
Text("Buy for \(product.price) $")
}
.foregroundColor(.blue)
}
}
}
.navigationTitle("")
.toolbar(content: {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
storeManager.restoreProducts()
}) {
Text("Restore Purchases ")
}
}
})
.onAppear(perform: {
storeManager.myProducts = []
storeManager.getProducts(productIDs: productIDs)
})
Code for the StoreManager:
class StoreManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
//FETCH PRODUCTS
var request: SKProductsRequest!
@Published var myProducts = [SKProduct]()
func getProducts(productIDs: [String]) {
print("Start requesting products ...")
let request = SKProductsRequest(productIdentifiers: Set(productIDs))
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("Did receive response")
if !response.products.isEmpty {
for fetchedProduct in response.products {
DispatchQueue.main.async {
self.myProducts.append(fetchedProduct)
}
}
}
for invalidIdentifier in response.invalidProductIdentifiers {
print("Invalid identifiers found: \(invalidIdentifier)")
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Request did fail: \(error)")
}
//HANDLE TRANSACTIONS
@Published var transactionState: SKPaymentTransactionState?
func purchaseProduct(product: SKProduct) {
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
} else {
print("User can't make payment.")
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchasing:
transactionState = .purchasing
case .purchased:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
transactionState = .purchased
case .restored:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
transactionState = .restored
case .failed, .deferred:
print("Payment Queue Error: \(String(describing: transaction.error))")
queue.finishTransaction(transaction)
transactionState = .failed
default:
queue.finishTransaction(transaction)
}
}
}
func restoreProducts() {
print("Restoring products ...")
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
Since everything works properly on all devices via USB debugging, I'm at a loss for how to move forward. Has anybody ever encountered this issue?