6

How do I get Transaction.currentEntitlements to return subscription auto-renewal transactions that happen while the app is closed?


I have implemented auto-renewing subscriptions in my macOS app.

I have a StoreManager that creates listeners on Transaction.currentEntitlements and Transaction.updates

If the subscription renews while the app is running, Transaction.updates receives the latest transactions, as expected.

However, When a renewal happens automatically while the app is not running, when the app is re-opened the Transaction.currentEntitlements does not return the renewal transaction.

Following the steps to reproduce:

  • Start the app and purchase an auto-renewing subscription
  • kill the app
  • wait for the subscription to expire and auto renew (monthly can be set to renew every 30 seconds when testing)
  • restart the app
  • Transaction.currentEntitlements returns nothing.

Checking the StoreKit Transactions debugging window when the app starts, renewal transactions that happened while the app was closed show as "not finished".

enter image description here

The non-finished transactions are the ones not returned.

If the subscription again gets renewed while the app is running, the listener on Transaction.updates gets fired and the new renewal plus any non-finished transactions are returned.

Here's the relevant code from the StoreManager

@MainActor
class StoreManager: ObservableObject {
    
    var updates: Task<Void, Never>? = nil
    var transactions: Task<Void, Never>? = nil

    init() {
        updates = updatesListenerTask()
        transactions = transactionsListenerTask()
    }

    @Published private (set) var transaction: StoreKit.Transaction?
    
    func updatesListenerTask() -> Task<Void, Never> {
        Task.detached(priority: .background) {
            for await result in Transaction.updates {
                Task { @MainActor in
                    do {
                        let transaction = try self.validateResult(result)
                        self.transaction = transaction
                        await transaction.finish()
                    } catch {
                        print("Failed verification =\(error.localizedDescription)")
                    }
                }
            }
        }
    }
    
    
    func transactionsListenerTask() -> Task<Void, Never> {
        Task.detached(priority: .background) {
            for await result in Transaction.currentEntitlements {
                Task { @MainActor in
                    do {
                        let transaction = try self.validateResult(result)
                        self.transaction = transaction
                        await transaction.finish()
                    } catch {
                        print("Failed verification =\(error.localizedDescription)")
                    }
                }
            }
        }
    }
    
    func validateResult(_ result: VerificationResult<StoreKit.Transaction>) throws -> StoreKit.Transaction {
        switch result {
        case let .verified(transaction):
            return transaction
        case .unverified:
            throw StoreManagerError.failedVerification
        }
    }
}

Update

Transaction.latest(for: <productId>) returns the latest finished product, so not the auto renewed one.

Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
  • 1
    So is StoreKit 2 essentially broken when it comes to auto-renewing subscriptions? I'm currently updating my code from StoreKit 1 (App Store receipt verification) to StoreKit 2 (Transaction.currentEntitlements). But if currentEntitlements doesn't work correctly, then I might as well stick with StoreKit 1. – Roberto Mar 23 '23 at 16:34
  • 1
    I was able to reproduce this problem in Xcode with an iOS app. This seems like such basic functionality that it's strange that it still hasn't been fixed after more than 18 months. Any idea if this is just an Xcode testing issue or does it affect apps in the wild? – Roberto Mar 23 '23 at 18:04
  • 1
    _"is StoreKit 2 essentially broken?"_… seems like it. My subscriptions are annual, so hopefully it'll be fixed by the time anyone wants to renew! – Ashley Mills Mar 24 '23 at 12:41
  • 2
    The main issue seems to be the auto-renew transaction failing to complete (as indicated by the warning icon in the Transactions window). However, this thread suggests that it's simply an Xcode testing bug: "Just got confirmation from someone working on this that it's just a bug in StoreKit testing when using StoreKit 2 - phew!" https://twitter.com/hybridcattt/status/1496131281792421899 – Roberto Apr 13 '23 at 01:53

0 Answers0