russell-archer / StoreHelper

Implementing In-App Purchases with StoreKit2 in Xcode 13 - 15 using SwiftUI, Swift 5.7 - 5.9, iOS 15 - 17 and macOS 12 - 14. Also supports tvOS and visionOS.
MIT License
407 stars 47 forks source link

Subscriptions renewed when the MacOS app was closed are not picked up by Storekit2 #50

Closed bogdanf closed 1 year ago

bogdanf commented 1 year ago

I'm seeing a really strange behavior in Xcode 14.3 (14E222a, Ventura 13.3) for a MacOS app with auto-renewable subscriptions.

Scenario:

  1. Launch the app (local Xcode testing) and purchase a subscription -> works OK.
  2. Let the app run and after a while the subscription renews and StoreHelper picks up the renewal alright.
  3. Close the app and let the subscription renew a few times "in the background."
  4. When reopening the app, the latest transaction retrieved by a call to storeHelper.subscriptionHelper.subscriptionInfo(for: "Monthly") is the last one seen when the app was running. All the transactions happening while the app was closed are not there.
  5. The Storekit 1 call in AppStoreHelper is picking up the "ghost" transactions quite well, but it only passes down the stream the ProductID(s) associated with those transactions, which is quite useless without a proper subscriptionInfo object.

Am I the only one seeing this? Is this going to happen in production too, or is it just a bug in local testing?

russell-archer commented 1 year ago

Thanks for letting me know. I had a very quick look to see what happens using the demo project. With local StoreKit testing I can see that subscription renewals happening while the app's not running are indeed NOT sent to the app when it re-opens, as I would have expected. I won't be able to look into this properly for a few days I'm afraid.

In the meantime, are you able to try this using sandbox testing (i.e. with your products defined in App Store Connect). Nobody has reported this as a problem before, so I wonder if this is related only to local StoreKit testing?

What I would expect to see happen is renewal transactions that happen while an app's not running to be sent through the normal Storehelper.handleTransactions() method once the app re-opens.

I'm a bit confused when you talk about the Storekit 1 call in AppStoreHelper picking up "ghost" transactions. That's only meant to support direct App Store purchases made outside the app. Are you saying that the paymentQueue(_:updatedTransactions) method is receiving subscription renewals?

russell-archer commented 1 year ago

I've looked into this a bit more and you're quite right: subscription renewals (even if there are multiple renewals) that happen when the app's not running ARE being detected when the app re-opens, but they're being picked up by the paymentQueue(_:updatedTransactions) method. And the transactions are not being properly handled.

Now I can see what's happening I'll hopefully be able to put a fix together quickly!

chriswitko commented 1 year ago

Honestly, I had and still have the same issue, but I thought this is how it works in local env. Because on prod env (App Store) I don't have this issue, however it was frustrating 😀, good that I'm not the only one with this issue

bogdanf commented 1 year ago

@russell-archer Thank you for looking into this. I wasn't clear at all when speaking about 'ghost transactions' indeed :-) I meant the transactions happening while the app was closed.

It could be a Storekit cache problem though, if I delete the ~/Library/Group Containers/group.com.apple.storekit/Library/Caches folder the missed transactions are retrieved without problems by the Storehelper.handleTransactions().

Testing now with the Sandbox.

bogdanf commented 1 year ago

@chriswitko Glad it works in production though, I was afraid something is very wrong with the Subscriptions on MacOS and they're not really usable.

bogdanf commented 1 year ago

OK, tested in the sandbox environment too, and it's the same as with local testing. Deleting the caches helps here too.

russell-archer commented 1 year ago

I've made some minor changes and done a fair bit of testing. I think subscriptions are now correctly auto-renewing when the app isn't running (i.e. they're picked up correctly when the app restarts). This is for local StoreKit and Sandbox testing. I don't want to do anything too drastic as I don't want to break something that is working correctly in production!

bogdanf commented 1 year ago

@russell-archer - Tested now the new version and it works perfectly in picking up and reporting the transaction ID too now vie productPurchased(_ productId: ProductId, transactionId: String)

The transaction returned by storeHelper.subscriptionHelper.subscriptionInfo(for:) is still the old one, but I guess this cannot be helped until the cache issue is solved by Apple.

Many, many thanks for the quick resolution!

russell-archer commented 1 year ago

Fantastic! Thanks for letting me know!

chriswitko commented 1 year ago

@russell-archer now it works properly :) thank you for the fix!