Open ciriousjoker opened 9 months ago
Speculation: This is kind of important, because calling this could result in a new customer being created in Chargebee because the subscription is being imported without the existing customer.
Can someone please look at this?
@ciriousjoker Thanks for raising the issue, we will fix this for flutter soon.
@cb-anurags I have one important question about this as well:
restorePurchases
functionality on app startup. The store then probably calls the same callback that the chargebee sdk uses internally. Could this lead to any issues?@ciriousjoker
By "call the store's native restorePurchases
functionality", do you refer to the Chargebee Android and iOS SDKs' Restore purchases method (with the customer object)?
If yes, then it should pretty much work as expected.
If not, can you elaborate on the methods you are using?
@cb-haripriyan
Im specifically talking about this function: https://pub.dev/packages/in_app_purchase#restoring-previous-purchases
We call that package's restore purchase functionality which gives us all the receipts in a stream. This is our way to ensure that users get access to the app even chargebee has the incorrect status.
In the past we tried relying on Chargebee alone but that lead to trust issues because lots of customer complained due to incorrect data and we therefore decided to keep the fallback mechanism permanently.
@ciriousjoker That method should restore the user subscriptions and return the stream of purchase tokens/receipts. But how do you sync these receipts to be stored in Chargebee?
@cb-haripriyan We don't. Currently we only store them in-memory to have a guaranteed to be accurate subscription status inside the app. Also, we store the latest receipt inside our database.
I was just wondering if the stream is also picked up by the Chargebee sdk and since we don't pass a customer id anywhere it might break something.
@cb-haripriyan After the general call, iirc the conclusion was that this might be causing issues because Chargebee doesn't get the uid if the stream is triggered by us and not via the Chargebee method. Do you have an ETA of when you know if this is causing issues and when a fix will be available?
@ciriousjoker
Looking at the implementation of the native restore method of flutter package (https://pub.dev/packages/in_app_purchase#restoring-previous-purchases), the android restore method is synchronous - That is the native method would receive the restored purchases receipt. This doesn't affect the subscription in Chargebee.
However the iOS method is async and the response of the restored purchases reach the SKPaymentTransactionObserver
listener which is registered inside the Chargebee iOS SDK. Hence the internal CB SDK listener would the receipt and it tries to resolve it to the customer which wouldn't be set. This will result in the restored subscription being moved to a customer with ID which is that of the subscription ID.
We have released a patch today with the 0.4.2 version, which takes in the customer object and restores the subscriptions. Would you be able to give it a try and let us know if this works?
@cb-haripriyan perfect, thanks for the investigation and the quick fix!
We'll roll out an update over the coming days. Unfortunately it'll be hard to evaluate if the error comes back since there's no way to find affected users directly, users just contacted our support with the issue.
@cb-haripriyan I've reviewed the v1.0.28 of the ios sdk as well as the v0.4.2 of the flutter sdk. I couldn't find any code that prevents the ios callback from being called in cases where the restorePurchases()
is called via the in_app_purchase
package.
What am I missing here. We cannot call Chargebee's sdk method directly, we need to call the method from in_app_purchases
, at least for now. And if I understood you correctly, in those cases, on iOS (not Android), the purchase receipts are still handled by Chargebee's sdk and will be imported as new customers in Chargebee since Chargebee's restorePurchases()
is never called.
@ciriousjoker The version 0.4.2 fixes the originally raised issue which was that the restorePurchases
method of the Chargebee Flutter SDK doesn't allow the passing of a Customer
object. Now the restorepurchase method of Chargebee takes in a customer and when it is invoked it would restore the subscriptions correctly to the customer.
Now with regards to using in_app_purchases
library along side the Chargebee SDK - since both the libraries are for similar functionality, the use of one along with the other can cause effects. That is, when you call the restore purchases method of Chargebee SDK, the in_app_purchases
SDK listener will also receive the events as well, since both the SDKs register their listeners on initialization. (This is behavior in iOS since the responses are handled via delegates/listeners).
Also when the restorePurchases
method of Chargebee SDK is called, the in_app_purchase
listener would also be called (for iOS).
A couple of workarounds I can think of right now:
in_app_purchases
listener would still receive the response since the listener is already set.restorePurchase
of in_app_purchases
and receiving all responses, you can follow it up a Chargebe SDK call with customer object which should sync the correct state. This however would cause back and forth changes of customer ID. We are looking at ways to prevent the Customer ID change, which should atleast prevent changing the customer to a default value.@cb-haripriyan The workaround seems like it should work and we'll try that.
However, one change I would suggest for the Chargebee sdk on iOS is this:
This would make the sdk more robust. Unfortunately we can't fork the iOS sdk directly, but I can create a PR nonetheless if you'd like me to.
@ciriousjoker Thanks for the input. This is indeed one of the ways we were considering. However we would need to take into account the overall SDK and parity of features b/w ios and andriod (and not just the restorePurchase method for iOS). We are considering few alternative approaches, which we solve all cases like these.
As per ios sdk documentation:
The ios sdk requires a customer, but the flutter sdk doesn't. How is that possible?? If we call this function without a customer, which customer is the subscription restored to?