I am testing subscription buying in my iOS app. I am utilizing Retailer Package 2. Sending to backend the transaction to confirm and write membership knowledge to DB. Upon backend returning success I end transaction and dismiss fee varieties.
I appear to have run into an issue. After few efficiently accomplished purchases with:
- Apple fee type showing accurately
- sandbox password type
- warning that I already bought the subscription (it is non-renewable static length subscription) and whether or not do I wish to purchase once more or not (I click on verify)
- affirmation type informing me that I accomplished buy
So it appeared as every thing is working positive. However then I began getting improper conduct – clicking on any choices in my UI that calls my ProductManager.swift like this:
ProductManager.shared.buy(productID: productID, isAutoRenewable: isAutoRenewable, quantity: quantity) { [weak self] success, error in
would not present any Apple fee type but my sendToBackend operate prompts as a result of iOS sends transaction to backend and it verifies with Apple and writes knowledge to DB. I might even immediately see my customized congratulating popup which is meant to indicate after accomplished buy (returned from backend).
And it is inconsistent. However proper now I can’t for the love of God make auto-renewable buy to indicate me any fee varieties, it simply silently processes every thing in my Node.JS:
{"transactionId":"2000000902832874","originalTransactionId":"20000008992983721","webOrderLineItemId":"200000009127659","bundleId":"some.bundle.id","productId":"some.product.id","subscriptionGroupIdentifier":"21647158","purchaseDate":1745246764000,"originalPurchaseDate":1744788721000,"expiresDate":1745247064000,"amount":1,"sort":"Auto-Renewable Subscription","inAppOwnershipType":"PURCHASED","signedDate":1745446227570,"setting":"Sandbox","transactionReason":"RENEWAL","storefront":"USA","storefrontId":"143441","value":9990,"forex":"USD","appTransactionId":"704404281845301369"}
Here is my buy and purchase funcs:
func buy(productID: String, isAutoRenewable: Bool, quantity: Int?, completion: @escaping (Bool, Error?) -> Void) {
Job {
// Guarantee merchandise are fetched earlier than continuing
if !isProductsFetched {
await fetchProducts()
}
var product = merchandise.first(the place: { $0.id == productID })
if product == nil {
await fetchProducts()
product = merchandise.first(the place: { $0.id == productID })
}
guard let finalProduct = product else {
completion(false, NSError(area: "StoreKit", code: 404, userInfo: [NSLocalizedDescriptionKey: "Product not found"]))
return
}
await self.purchase(product: finalProduct, isAutoRenewable: isAutoRenewable, quantity: quantity, completion: completion)
}
}
non-public func purchase(product: Product, isAutoRenewable: Bool, quantity: Int?, completion: @escaping (Bool, Error?) -> Void) async {
do {
let end result = attempt await product.buy()
swap end result {
case .success(let verification):
swap verification {
case .verified(let transaction):
// Ship transaction knowledge on to backend
let backendSuccess = await self.sendToBackend(transaction: transaction, productId: product.id, quantity: quantity, isAuto: isAutoRenewable)
if backendSuccess {
// Guarantee backend processed earlier than ending the transaction
attempt await transaction.end()
completion(true, nil)
} else {
let error = NSError(area: "BackendError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Backend validation failed"])
print("❌ Backend validation failed")
completion(false, error)
}
case .unverified(_, let error):
completion(false, error)
}
case .userCancelled, .pending:
completion(false, nil)
@unknown default:
completion(false, nil)
}
} catch {
completion(false, error)
}
}
May it’s unstable sandbox setting?