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 information 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 kind showing appropriately
- sandbox password kind
- warning that I already bought the subscription (it is non-renewable static period subscription) and whether or not do I need to purchase once more or not (I click on verify)
- affirmation kind informing me that I accomplished buy
So it appeared as every thing is working high-quality. 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 kind but my sendToBackend operate prompts as a result of iOS sends transaction to backend and it verifies with Apple and writes information to DB. I might even immediately see my customized congratulating popup which is meant to point out 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 point out 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","worth":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 outcome = strive await product.buy()
swap outcome {
case .success(let verification):
swap verification {
case .verified(let transaction):
// Ship transaction information 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
strive 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?