2

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?

  • I'm in the same case. Based on my experience (testing locally) `Transaction.currentEntitlements` may return an expired subscription... Which contradicts the documentation. – vomi May 13 '23 at 09:03

0 Answers0