Closed ubuntudroid closed 2 years ago
Are you manually restoring purchases anywhere to migrate users?
The PurchaserInfo will always read from the cache first (if available) then update the cache through the network in the background. That's what you may be experiencing here, but it's a little unclear at what step do you expect the purchases to be migrated to RevenueCat?
If you determine the user is not subscribed in RevenueCat, but subscribed in your old system, you can programmatically trigger a restore. This will sync the subscription status with RevenueCat, but does require a network connection to complete.
Currently I don't manually restore purchases (although reading through the discussion forums I figured I might have to).
But the interesting thing is: why is the first PurchaserInfo
empty and the second one (even if triggered only a few seconds later) is populated - even without ever calling restoreTransactions()
? Why do I even get the first empty one? Everything would be fine, if the first (empty) one wasn't returned by the getPurchaserInfoWith()
callback and onReceived()
. 🤔
My current plan for a (partial) workaround is: if I detect a discrepancy between RC and my local subscription handling, I trigger a purchase restore and discard the empty PurchaserInfo
. This should work as long as I have some local data left from before the update to check against. But it won't work for returning users who just installed the app again and where I can't compare. They will have no access to my premium features until getPurchaserInfoWith()
is triggered again when they navigate through the app and stumble on another premium feature.
I hope my explanation makes sense! 😅
Yeah, unless you manually trigger a restore, our initial purchaser info will be empty since we haven't seen any receipts. Sometimes, we may get a receipt if a renewal happens to have happened in between, but not usually the case. Perhaps more frequent in sandbox.
Okay, so I will now always trigger a restore regardless of my old subscription state if it is the first start of the app after install/update to a RevenueCat enabled version.
I'll report back in case the empty PurchaseInfo
still pops up after a restore because even with the workaround outlined above the second case cannot be circumvented:
it won't work for returning users who just installed the app again and where I can't compare. They will have no access to my premium features until getPurchaserInfoWith() is triggered again when they navigate through the app and stumble on another premium feature.
@jeiting I've implemented restore as outlined in my last comment. However I still get an empty PurchaseInfo
in onReceived()
after (according to the log) the SDK correctly fetched the purchase history, but has not yet checked them for entitlements. This happens afterwards as per the log (see below, it's already filtered and only contains relevant lines, grep for onReceived
for PurchaseInfo
objects returned by onReceived()
).
As the log shows the first PurchaseInfo
object should not be sent to the listeners until the state of the purchases fetched from history has been verified by the SDK against the backend/Google Play which only happens afterwards.
Thus my idea for a temporary (!) workaround: can we always just safely ignore the first PurchaseInfo
coming from the SDK after install / upgrade to a RC enabled version?
@jeiting @rkotzy any insights? Is the workaround outlined in my previous post a valid one?
I unfortunately can't ship without this fixed as I will face a whole lot of (rightly) angry users if I don't handle this properly: in my app certain settings are automatically disabled when the user is not entitled to premium anymore - and they are not automatically reenabled later when they are entitled again because those are opt-in settings. 💥 🤷 And I don't really want to work around that setting handling part because in the regular (non-restore) case the current handling provides the best user experience.
reopening for discussion, sorry I'd missed this ticket. This is a valid use case, we've been discussing it here as well.
assuming that the first purchaserInfo
you get might be outdated will work, with some caveats:
purchaserInfo
will update automatically if it's been more than 5 mins since the last refresh. So waiting for an update on purchaserInfo
won't work if the user opened the app twice in less than 5 mins. This shouldn't be a problem in your case because you don't need to skip purchaserInfo more than once - you only need it for that migration step, and you should be safe afterwards. purchaserInfo
will ever update. So you should set up a timeout in your app so that you can continue the flow if purchaserInfo
hasn't arrived yet. In your case, you could just fall back to the value you had before RC.In the future, we'll have to come up with a better system and API to aid in these cases. See the discussion in the attached issue.
Thanks for the update! 🙏 Sorry for missing that other ticket, thought I had thoroughly searched the other issues for similar ones, but apparently I didn't. 😓
Dropping the very first PurchaserInfo
unfortunately proved too flaky as there were several edge cases (mostly due to threading) which made this unnecessarily complicated. I now worked around the issue by not toggling premium features off right away when a missing entitlement is detected (as it is the case for the empty first PurchaserInfo
object), but instead just guard their getters with a premium check, so the next time they are checked they will be reported as off. In most cases this will enough to make the migration transparent for our users.
Looking forward to the changes in the SDK - I'll stay subscribed to this issue. Guess it will be closed once the changes are shipped? Or is there some other place I should monitor to follow progress?
I know this is an old issue, but want to check in to make sure we understand the problem and if there's a current workaround. Is the problem with the onReceived()
in the UpdatedPurchaserInfoListener
or the restorePurchases
ReceivePurchaserInfoListener
?
The restorePurchases
call should not return a PurchaserInfo from the cache and always have the latest entitlement status.
@rkotzy The problem is with onReceived()
. I've outlined our workaround in https://github.com/RevenueCat/purchases-android/issues/161#issuecomment-646699852 . It seems to work fine so far as long I maintain a somewhat lenient approach to removing access to premium features.
@ubuntudroid I don't know if you've seen it, but we added a cache policy object that allows you to configure the behavior now! https://github.com/RevenueCat/purchases-android/pull/546 I'm going to close this issue, but definitely feel free to open another if needed! Thank you for your patience, I know this is an older issue 😄
I don't know if it has anything to do with the discussion. I have a problem with the following flow. My app needs login to be a subscriber. After logging in and subscribe everything works normally. If I clear the app's cache and open it again and sign in, PurchaserInfo doesn't come with active subscriptions. If I uninstall and reinstall the app, I log in also does not come with active subscriptions. Any clues?
@mdmota I replied on the other ticket, let's keep the conversation in that one 👍
ok , i
Em sex., 26 de ago. de 2022 às 18:57, Andy Boedo @.***> escreveu:
@mdmota https://github.com/mdmota I replied on the other ticket, let's keep the conversation in that one 👍
— Reply to this email directly, view it on GitHub https://github.com/RevenueCat/purchases-android/issues/161#issuecomment-1228994880, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFCH45LLCH76MTTCQ6TU3VLV3E4SXANCNFSM4N2WG7LA . You are receiving this because you were mentioned.Message ID: @.***>
library version: 3.2.0
Steps to reproduce:
I've added some handling to the app to make migration for existing users as smooth as possible: If the app is started offline after the user has updated to the new version I use my old entitlement data until RevenueCat SDK reports that it could successfully retrieve
PurchaserInfo
(either fromgetPurchaserInfoWith()
oronReceived()
). As soon as I get aPurchaserInfo
I switch over to RevenueCat as the single source of truth and never check my old entitlement data again.However what I've observed is (continuing from above):
getPurchaserInfoWith()
).getPurchaserInfoWith()
is executed (I trigger it manually by trying to access a premium feature) and returns aPurchaserInfo
(both in the success listener and inonReceived()
), but - lo and behold - it is completely empty! So:getPurchaserInfoWith()
again or put the app into background and foreground it again: a filledPurchaserInfo
is returned and now:So the question is: why do I get an empty
PurchaserInfo
the first time after coming online? This creates a very weird situation where the user has no access to my premium features until the "real"PurchaserInfo
arrives. I found no hint, that I could use to discard the firstPurchaserInfo
unfortunately - it looks perfectly valid other than that the entitlements and subscriptions are empty (as if the user didn't have bought the subscription).