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

Purchases.getOfferings() returning different object on Android vs iOS #727

Open
5 tasks done
wmonecke opened this issue Sep 2, 2023 · 4 comments
Open
5 tasks done
Labels
bug Something isn't working

Comments

@wmonecke
Copy link

wmonecke commented Sep 2, 2023

Describe the bug
I was able to get my offerings as follows:

Purchases.getOfferings()
      .then((offerings) => {
        console.log('offerings:', offerings);

        if (offerings?.current.availablePackages.length !== 0) {
          return this.setState({
            offerings: offerings?.current?.availablePackages,
          });
        }

        return this.setState({ offerings: false });
      })
      .catch((error) =>
        console.log('error getting offerings:', error),
      );

However, the elements inside the availablePackages array are different in Android vs. on iOS.

Is this intended? I didn't find anything related to this in the docs.
What could I be doing wrong?

  1. Environment
    1. Platform: iOS/ Android
    2. SDK version: "react-native-purchases": "^6.3.0",
    3. OS version: latest
    4. React Native version: 0.72.2
    5. How widespread is the issue. Percentage of devices affected - Local only

availablePackages item on ios:

{
            "packageType": "MONTHLY",
            "identifier": "$rc_monthly",
            "product": {
                "priceString": "$3.49",
                "productType": "NON_CONSUMABLE",
                "discounts": [],
                "description": "Enjoy the all-access \"Plus\" version",
                "currencyCode": "USD",
                "title": "....",
                "price": 3.4899999999999998,
                "subscriptionPeriod": "P1M",
                "productCategory": "SUBSCRIPTION",
                "identifier": "....plus.1month",
                "introPrice": {
                    "cycles": 1,
                    "periodUnit": "DAY",
                    "priceString": "$0.00",
                    "period": "P3D",
                    "periodNumberOfUnits": 3,
                    "price": 0
                }
            },
            "offeringIdentifier": "default"
        },

vs android

{
            "offeringIdentifier": "default",
            "product": {
                "presentedOfferingIdentifier": "default",
                "subscriptionOptions": [
                    {
                        "introPhase": null,
                        "freePhase": null,
                        "isPrepaid": false,
                        "presentedOfferingIdentifier": "default",
                        "fullPricePhase": {
                            "offerPaymentMode": null,
                            "billingCycleCount": 0,
                            "price": {
                                "currencyCode": "EUR",
                                "amountMicros": 3990000,
                                "formatted": "€3.99"
                            },
                            "recurrenceMode": 1,
                            "billingPeriod": {
                                "iso8601": "P1M",
                                "value": 1,
                                "unit": "MONTH"
                            }
                        },
                        "isBasePlan": true,
                        "billingPeriod": {
                            "iso8601": "P1M",
                            "value": 1,
                            "unit": "MONTH"
                        },
                        "productId": "....plus.1month",
                        "tags": [],
                        "pricingPhases": [
                            {
                                "offerPaymentMode": null,
                                "billingCycleCount": 0,
                                "price": {
                                    "currencyCode": "EUR",
                                    "amountMicros": 3990000,
                                    "formatted": "€3.99"
                                },
                                "recurrenceMode": 1,
                                "billingPeriod": {
                                    "iso8601": "P1M",
                                    "value": 1,
                                    "unit": "MONTH"
                                }
                            }
                        ],
                        "storeProductId": "....plus.1month:p1m",
                        "id": "p1m"
                    }
                ],
                "introPrice": null,
                "currencyCode": "EUR",
                "priceString": "€3.99",
                "subscriptionPeriod": "P1M",
                "productCategory": "SUBSCRIPTION",
                "price": 3.99,
                "title": "",
                "productType": "AUTO_RENEWABLE_SUBSCRIPTION",
                "discounts": null,
                "defaultOption": {
                    "introPhase": null,
                    "freePhase": null,
                    "isPrepaid": false,
                    "presentedOfferingIdentifier": "default",
                    "fullPricePhase": {
                        "offerPaymentMode": null,
                        "billingCycleCount": 0,
                        "price": {
                            "currencyCode": "EUR",
                            "amountMicros": 3990000,
                            "formatted": "€3.99"
                        },
                        "recurrenceMode": 1,
                        "billingPeriod": {
                            "iso8601": "P1M",
                            "value": 1,
                            "unit": "MONTH"
                        }
                    },
                    "isBasePlan": true,
                    "billingPeriod": {
                        "iso8601": "P1M",
                        "value": 1,
                        "unit": "MONTH"
                    },
                    "productId": "....plus.1month",
                    "tags": [],
                    "pricingPhases": [
                        {
                            "offerPaymentMode": null,
                            "billingCycleCount": 0,
                            "price": {
                                "currencyCode": "EUR",
                                "amountMicros": 3990000,
                                "formatted": "€3.99"
                            },
                            "recurrenceMode": 1,
                            "billingPeriod": {
                                "iso8601": "P1M",
                                "value": 1,
                                "unit": "MONTH"
                            }
                        }
                    ],
                    "storeProductId": "....plus.1month:p1m",
                    "id": "p1m"
                },
                "description": "...!",
                "identifier": "....plus.1month:p1m"
            },
            "packageType": "MONTHLY",
            "identifier": "$rc_monthly"
        },
@wmonecke wmonecke added the bug Something isn't working label Sep 2, 2023
@RCGitBot
Copy link
Contributor

RCGitBot commented Sep 2, 2023

👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!

@vegaro
Copy link
Contributor

vegaro commented Sep 4, 2023

Thanks for pointing that out. defaultOption and subscriptionOptions are Google specific and only returned in Android devices. We have actually just noticed that they should be optional in the Typescript definitions but they are not, which is an issue. We will evaluate if we make them optional or return them as null in iOS. In the meantime, can you add checks so the properties are only accessed in iOS?

Sorry if that is confusing, we'll try to make it less confusing in a future release.

@wmonecke
Copy link
Author

wmonecke commented Sep 4, 2023

Yeah, at the moment I am doing something like this:

    const periodLengthInMonths =
      Platform.OS === 'android'
        ? selectedPackage.product.defaultOption.billingPeriod.value
        : selectedPackage.product.introPrice.periodNumberOfUnits;

@joshdholtz
Copy link
Member

@wmonecke Hey! 👋 I just noticed that your example above is grabbing two different types of periods 🤔

  • selectedPackage.product.defaultOption.billingPeriod.value is the billing period for the sub (not the intro)
  • selectedPackage.product.introPrice.periodNumberOfUnits is the billing period for the intro price (not the sub)

Design of defaultOption

The placing of defaultOption and subscriptionOptions in this response was designed for developers if they needed to do something super specific on Google Play (ex: if you had multiple different offers and you wanted to choose something specific for the user).

Values of defaultOptions are backsupported into the existing offering response that iOS uses. Example:

  • The selectedPackage.product.defaultOption.billingPeriod values are put into selectedPackage.product. subscriptionPeriod
  • The selectedPackage.product.defaultOption.introPhase values are put into selectedPackage.product.introPrice

Getting your periodLengthInMonths

With the following examples, you shouldn't need to do any special checking of platforms 🤞

Subscription period

So, I think to calculate your periodLengthInMonths variable from your above example, you would only need to look at selectedPackage.product. subscriptionPeriod for both platforms. This returns a value P1M or P3M but we should really provide a nicer period object in there to make this easier.

Intro Period

If you are looking for the intro period, you should look into selectedPackage.product.introPrice.periodNumberOfUnits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants