-
-
Notifications
You must be signed in to change notification settings - Fork 648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IOS check if autorenewal subscription is still active #275
Comments
I'm working on figuring this out as well. I haven't tested it yet, but from what I'm reading I'm gathering that it's possible by creating a "shared secret" in iTunes Connect and passing this to validateReceiptIos with the key 'password'. I believe this will then return a JSON object which will contain a code indicating the validation status of the subscription and the keys latest_receipt, latest_receipt_info, and latest_expired_receipt info, among others, which you can use to determine the subscription status. I am literally just figuring this out so I have yet to test it. It's what I'm putting together from the issues and Apple's docs. If this works, it really should be made very clear in the documentation instead of being buried in the issues. EDIT: I can confirm that the process I mentioned above works. I think we should work to get a full explanation of this in the docs. I would implement something like this on app launch to determine whether a subscription has expired:
|
Brilliant! Just some things that arent so trivial about your code;
const expiration = renewalHistory[renewalHistory.length - 1].expires_date_ms instead of (probably just a typo) const expiration = latestRenewalReceipt[latestRenewal.length - 1].expires_date_ms
You can create your shared secret key for your In App paments and use it on your app Steps are here: https://www.appypie.com/faqs/how-can-i-get-shared-secret-key-for-in-app-purchase +1 to update the docs, also, maybe @dooboolab you can separate the use cases in IOS and Android seems there are a few things different. I can help you if you want to. Regards |
What happens with autorenewal subscriptions? Seems that the expires_date_ms is the first expiration date, it is not updated I have tested this:
Any ideas? My bad, the expiration date seems to be updated, it just takes a while. I will leave this comment here in case anyone is in the same scenario. Regards |
Oops yea you are correct, that was a typo. I had changed the name to make its meaning more obvious but forgot to change all occurrences. I've edited it, thanks. And I haven't had that exact scenario with expiration date but there was some stuff with it not autorenewing at all, though it somehow resolved on its own (which worries me, but I can't reproduce so idk what else to do). The issue you had is a fairly common one. It's expected behavior on Apple's end, so you should leave a buffer period for the subscription to renew before unsubscribing the user. This issue on SO explains in more detail: https://stackoverflow.com/questions/42158460/autorenewable-subscription-iap-renewing-after-expiry-date-in-sandbox |
Thanks! Great info, could be the reason About this issue, i think the @kevinEsherick code should be on the docs 👍 Its a great way to check subs! |
Yes. I would appreciate a neat doc in |
Hi guys. I've added Q & A section in readme. Hope anyone of you can give us a |
I'll look into making a PR in the next few days :) |
I am also looking to use this library specifically for subscriptions. Both iOS and Android. Documenting the proper way to determine if a user has a valid subscription would be greatly appreciated. 😄 |
@curiousdustin Apple's implementation on this is really terrible if you refer to medium. Since you need to handle this kind of thing in your backend, we couldn't fully support this in our module. However, you can get |
So are you saying the solution that @marcosmartinez7 and @kevinEsherick are working on in this thread is NOT a solution, and that a backend server other than Apple's is necessary to confirm the status of an iOS subscription? From reading the Medium article you posted along with the Apple docs, it does seem that using a server is preferred, but it is not impossible to determine subscription status with device only. |
Sorry that I've missed some information in my writing. I will manage this now. However, it isn't impossible to still try out with I think currently this is the solution to work out for checking |
Hey guys, sorry it's been more than a few days, I've been caught up in work but I'll still submit that PR to update the README. @curiousdustin the method I wrote about above definitely works and I'll add that to the docs. I'll submit the PR tonight or tomorrow :) |
Thanks the the update. One more thing I noticed from your example.
In my testing, purchases and renewalHistory aren't necessarily in any particular order. Wouldn't we need to sort them or something to verify we are using the one we intend to? |
Same here. Purchases and renewalHistory are definitely not ordered, so we do have to sort first. In dev, that ends up being a lot of iterations. |
Here is the function I am using that works on both Android and iOS, properly sorting on iOS to ensure we get the latest receipt data:
|
On the android scenario, if the subscription is auto-renewable it will be returned on availablePurchases |
@curiousdustin @andrewzey You're right, purchases is not ordered. renewalHistory/latest_receipt_info, however, is always ordered for me. I remember realizing that purchases wasn't ordered but thought I had found some reason that this wasn't actually of concern. I'll look into this in a couple hours once I get home. I don't want to submit a PR til we have this figured out. |
@kevinEsherick Thanks! In my case, neither the purchases nor renewalHistory were ordered. |
@kevinEsherick @andrewzey Can you guys give |
Sure I'll prepare it right after we're done with our public app launch =). |
I was waiting for more conversation regarding my last comment. I brought up some issues that remain unresolved. Please see above for reference. Once we get that sorted out one of us can make a PR. |
@kevinEsherick Ah sorry, I missed that.
But I did it anyways in service of trying to be accurate, and compensating for possible discrepancies in the actual API response from what Apple documents. I don't think a sort operation there will be very expensive, given the total number of receipts you're likely to encounter for auto-renewing subscriptions. |
Any ETA on the PR? I am considering moving over from this package as it does not handle this case at all. |
@schumannd Given that the PR would be only to update the docs, you can move over to I've confirmed that my code snippet does in fact work without issue in production with our recently launched app: https://itunes.apple.com/us/app/rp-diet/id1330041267?ls=1&mt=8 EDIT I'll definitely make the PR (I have it in my "Give back to OSS" list in our Trello), but after the black friday weekend craziness 😄 |
@schumannd I second what @andrewzey said. Everything a PR would say is contained here in this post. I've been meaning to get around to it but it took us awhile to sort out exactly what needs to be done, and that mixed with travel and hectic startup hours mean I haven't had the time to PR it yet. I still plan to soon, but anyone else can step up in the meantime if they'd like. And @andrewzey congrats man! Looks great, I'll give it a download! |
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information. |
Perhaps this whole flow needs clarifying in the documentation? Especially when it comes to the Auto-renewing subscription? It is very unclear to a newcomer whether you are able to check the I suggest the best place for this would be in a more complete working example? Would people be interested in this? If I get some time, I could work on this? |
@alexpchin yes that would definitely save a ton of dev time and your karma will get crystal clean:D |
Agree! Would anyone be interested in #856 ? |
Hi, @andrewzey's method has worked great for us until yesterday when we were suddenly no longer to validate any receipts for our subscriptions - we're getting a JSON parse error back from iOS when calling validateReceiptIos(). I take it no one else has ran into this...? The only change that was made since yesterday was the addition of a promo code on ITC which we have since removed to help eliminate variables. Is there any reason why a receipt should fail JSON parsing? It fails for every receipt returned - not just the receipt at index 0 of sortedAvailablePurchases. The code is basically identical to andrewzey's example - I've omitted everything after validateReceiptIos since the error is thrown there. We're running RN 0.61.4, RNIap: 4.4.2, and iOS 13.3.1 We've tried:
We're wondering if we weren't using finishTransactionIOS correctly when we made the sandbox purchases? What's really strange is when we validate the receipt using this online tool, everything looks normal and we can see all of the receipt metadata.
|
Question regarding the code @andrewzey placed. Wouldn't Also, isn't verifying the receipt from the app itself not discouraged? |
@doteric Could you point me to where they mention its discouraged? I know that you can set up server side notifications, but it seems much easier from my perspective to handle this validation on the client instead of the server. |
@doteric yes Date.now() is the device time so it could be worked around. Yet the chances of a user doing this are minuscule, and even other methods could be worked around for an endless subscription. For example if using a simple server side validation, they could enter airplane mode prior to opening the app to prevent the app from realizing the subscription is expired. Of course there are other protections you could put in place, but my point is that client side using Date.now() is certainly functional. @captaincole I don't have the docs on hand but I can confirm that I too have read that client side validation is discouraged. I read it in Apple docs I believe. That being said, I think client side gets the job done. |
About client-side receipt validation on iOS: |
Hi, I was trying one of the approaches discussed in this thread, using validateReceiptIos and the latest_receipt_data (comparing expires_date_ms with actual date). It worked great while developing in Xcode. However, when I tested it in Testflight it didn't work anymore. Its hard to debug so I am not being able to identify the exact problem, it seems it is not getting the receipt data. Did anyone have a similar issue with testflight? Thanks in advance! |
+1 |
@asobralr @Somnus007 I may be wrong, but I don't think you can test IAPs with testflight since users can't make purchases through testflight. Apple does not provide great opportunities for testing purchases in production-like environments |
Correct. You can't even simulate failure scenarios in sandbox, which is a shame. 😞 |
Hi @kevinEsherick , thanks for your reply. You may be wrong. User can make purchase through teslflight. On testflight, it seems that user have to login a sandbox account which has the same email address with its real apple account. Then everything works well. BTW, will getPurchaseHistory trigger the Itunes login popup in production env? |
Looks like ios 14 breaks this solution due to the fact that there are issues when you call getAvailablePurchases() before calling requestSubscription(). |
had some troubles until i've passed object like:
with minor thing: think that last here's my update:
|
with this if after plan expiration if we validate the receipt token it adds new entry with extended expiry_date |
How implement apple button 'Restore Pusrchases' in 2024? |
what if user will his mobile's date and time , it will not working |
Version of react-native-iap
2.2.2
Platforms you faced the error (IOS or Android or both?)
IOS
Expected behavior
Using the RNIAP api we could check if a autorenewal subscription is still active
Actual behavior
On android im doing this to check that:
On ios there is no flag to check that, and the getAvailablePurchases method returns all the purchases made, even the subscriptions that are not active at the moment.
Is there a way to check this?
Regards,
Marcos
The text was updated successfully, but these errors were encountered: