I'm implementing auto renewable subscriptions with StoreKit 2, but I'm getting transaction updates when a subscription expires. The idea is to update the purchased products when a subscription expires by listening to a hook. I'm testing this from Xcode by cancelling the subscription and waiting for the expiration to happen.
I'm using Transaction.updates for listening to transaction updates. I also used as a reference the Apple's project example for implementing in-app purchases.
This is the method for listening to transaction updates:
func listenForTransactions() -> Task<Void, Error> {
return Task.detached {
//Iterate through any transactions that don't come from a direct call to `purchase()`.
for await result in Transaction.updates {
do {
let transaction = try self.checkVerified(result)
//Deliver products to the user.
await self.updateCustomerProductStatus()
//Always finish a transaction.
await transaction.finish()
} catch {
//StoreKit has a transaction that fails verification. Don't deliver content to the user.
print("Transaction failed verification")
}
}
}
}
and this one is for updating the purchased subscriptions:
@MainActor
func updateCustomerProductStatus() async {
var purchasedProducts: [Product] = []
// Iterate through all of the user's purchased products.
for await result in Transaction.currentEntitlements {
do {
// Check whether the transaction is verified. If it isn’t, catch `failedVerification` error.
let transaction = try checkVerified(result)
// Check the `productType` of the transaction and get the corresponding product from the store.
switch transaction.productType {
case .autoRenewable:
if let revocationDate = transaction.revocationDate {
//do nothing if transaction was revoked
print("Transaction was revoked on \(revocationDate)")
return
} else if let expirationDate = transaction.expirationDate,
expirationDate < Date() {
// Do nothing, this subscription is expired.
return
} else {
if let subscription = subscriptions.first(where: { $0.id == transaction.productID}) {
// Provide access to the product
purchasedProducts.append(subscription)
}
}
default:
break
}
} catch {
//storekit has a transaction that fails verification, don't delvier content to the user
print("Failed - error retrieving products \(error)")
}
}
//finally assign the purchased products
self.purchasedSubscriptions = purchasedProducts
}
This means that updateCustomerProductStatus()
has to be called manually to check whether a subscription is expired or not. I guess it could be because the expiration of a subscription is not considered a transaction update? If that's the case - Is there any other hook to listen to expirations?