Skip to content
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 subscription expiry is not handled #229

Open
keesvandieren opened this issue Sep 26, 2020 · 6 comments
Open

iOS subscription expiry is not handled #229

keesvandieren opened this issue Sep 26, 2020 · 6 comments

Comments

@keesvandieren
Copy link
Member

Please ensure you have given all the following requested information in your report.

Issue details, reproduction steps/code

The iOS Robovm implementation is not handling subscription expiry.

If you have ordered a subscription once, you currently have access for life.

Subscription receipts should be handled.

Version of gdx-pay and/or relevant dependencies

1.3.0

Stacktrace

N/A

Please select the affected platforms and payment service implementation

  • [ X] apple robovm
@keesvandieren
Copy link
Member Author

Parsing the Receipt seems to be fairly complicated. A Swift example is shown here:

https://github.com/andrewcbancroft/SwiftyLocalReceiptValidator/blob/master/ReceiptValidator.swift

Has anybody implemented this in Kotlin or Java?

@keesvandieren
Copy link
Member Author

Related to: #167.

Approach I'm planning to follow:

  • extend class Transaction with field subscriptionValidUntil. This will be filled with transaction startDate incremented with Product subscription incremented with Billing Grace Period (6 days for weekly, 16 days for longer subscriptions).
  • use this field, to validate transactions in the Java logic.
  • see if we can also populate this field in Google Play implementation.

Additionally, server validation can be used, but I currently have not enough time to implement that properly. Maybe in 2 or 3 months I have time

@keesvandieren
Copy link
Member Author

keesvandieren commented Oct 3, 2020

After some more thinking, I am proposing the following changes to support basic end-date calculation in Google Play and App Store, without receipt verification:

  • Rename class FreeTrialPeriod to SubscriptionPeriod
  • Add Information.subscriptionPeriod
  • Add field: Transaction.information, which is a reference to the related Gdx Information instance
  • In Transaction, add a method: @Nullable public Date calculateMaximumUsageDate(int gracePeriodInDays). This uses Transaction.purchaseTime, adds the subscriptionPeriod, then adds the gracePeriodInDays, and returns that Date.

Apps have to maintain billing grace periods themself. On iOS App Store, the period is dictated by Apple; however, enabling or disabling billing grace period is to be chosen by the developer. On Google Play, the developer can choose whether to enable billing grace period, and, if enabled, can choose from a number of predefined values. Billing grace period is not exposed through payment apis (on Google Play and App Store).

External links:

Eventually, we can add the billing grace period to Offer, but that would only work for Google Play, as for App Store it is decided by Apple. So that is why I prefer to keep it out.

@MrStahlfelge what do you think of this? (or any other reader interested in subscriptions)

@MrStahlfelge
Copy link
Member

I am not really into subscriptions (don't using them), but what you suggest seems viable. As you are using subscriptions, best is if you try in your fork if it works out for you. And if it does, let's add it to gdx-pay!

@aberkowski
Copy link
Contributor

@keesvandieren :

  • have you fixed this bug?
  • is this (not expiring subscriptions) apply to Non-renewing subscriptions also?
  • is subscriptions expire properly on Google Play?

@keesvandieren
Copy link
Member Author

keesvandieren commented Dec 29, 2023

@aberkowski it is not solved in gdx-pay yet. Apple returns all the historical subscriptions as of now. Receipt validation in Java/Kotlin seems to be hard to implement, didn't try it as I have no time for it.

How I handle it now:

  • find the newest Transaction (in handlePurchase or handleRestore)
  • calculate the subscription end date of the transaction
val isPurchased = lastPurchaseValidUntilMillis > System.currentTimeMillis()

This doesn't take into account refunds, and also when user changes the clock (back in time) it can use the app with an old subscription.

One thing you could implement, is a backend which retrieves the Apple events and then call an API to your own backend to see whether the subscription hasn't been refunded. See https://developer.apple.com/help/app-store-connect/configure-in-app-purchase-settings/enter-server-urls-for-app-store-server-notifications/ for more info.

Also, https://github.com/libgdx/gdx-pay/tree/master/gdx-pay-server is available as a starting point for server-side receipt validation but I've never used it; seems @noblemaster has some understanding and might actually use it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants