I have run some tests on my copy of StoreKit testing project. When the app is not active, and a renewal comes through, it will be unfinished. The listener task you have in Transaction.updates might not catch it.
Question:
Does your app handle unfinished transactions?
You need to listen for Transaction.unfinished, and finish any verified transactions. Either call it on the next launch, or create another Task to listen for unfinished.
func processUnfinishedTransactions() async {
for await result in Transaction.unfinished {
switch result {
case .verified(let verified):
// Always finish verified transactions
await verified.finish()
case .unverified(let unverified, _):
// Handle unverified
}
}
}
If you check the Understanding StoreKit Workflows sample from WWDC25, notice they have 3 things going on in the Store.swift file:
Task(priority: .background) {
// Finish any unfinished transactions -- for example, if the app was terminated before finishing a transaction.
for await verificationResult in Transaction.unfinished {
await handle(updatedTransaction: verificationResult)
}
// Fetch current entitlements for all product types except consumables.
for await verificationResult in Transaction.currentEntitlements {
await handle(updatedTransaction: verificationResult)
}
}
Task(priority: .background) {
for await verificationResult in Transaction.updates {
await handle(updatedTransaction: verificationResult)
}
}
Although it uses @Observable, your shared singleton should be able to keep these tasks alive. The same principles apply.