Android In-App Billing V5 subscription with trial period
Asked Answered
A

2

10

Google has updated its billing system and there is no full information how to deal with it.

Thus, instead of SkyDetails we have class ProductDetails. This object we can receive in callback of billingClient.queryProductDetailsAsync(). Then we can call getSubscriptionOfferDetails() on this object and get access to list of ProductDetails.PricingPhases. For example, if product has 2 offers(base and trial offer) we get list of 2 ProductDetails.PricingPhases.

Then when user want to buy a product we use this(from official doc):

val offerToken = productDetails.offerDetails(selectedOfferIndex).offerToken

What is selectedOfferIndex ? Should we always select first item or it depends?

Thanks everyone in advance.

Angularity answered 23/5, 2022 at 15:51 Comment(3)
Since getSubscriptionOfferDetails() returns a type List<ProductDetails.SubscriptionOfferDetails>, you need a singular object of type ProductDetails.SubscriptionOfferDetails, so the selectedOfferIndex is the index of the item that the user has selected from the list of offers available. More info on api docs: developer.android.com/reference/com/android/billingclient/api/…Linearity
My understanding is that if you don't pass offerToken for the free trial, the trial won't start for the user. Please correct me if I'm wrong. I also assume that the base offer is always the first in the list, please correct me if I'm wrong.Greensand
@Angularity did you got solution ? first item enough or not ?Rebak
T
4

The selectedOfferIndex depends on the offer the developer want to give to the users.

We have to loop through the total offers(getSubscriptionOfferDetails()) and use the token for the offer we want to give.

ProductDetails productDetails;
String offerToken = "";
        if (productDetails.getSubscriptionOfferDetails() != null) {
            for(int i = 0; i < productDetails.getSubscriptionOfferDetails().size();i++) {
                offerToken =  productDetails.getSubscriptionOfferDetails().get(i).getOfferToken();
                if(!offerToken.isEmpty()){
                    break;
                }
            }
        }

if there is only base plan then only one token is returned.

if there is base plan and free tril offer then getSubscriptionOfferDetails().size() will return 2

With Base + trial, when I pass 0th index token enter image description here

With Base + trial, when I pass 1st index token enter image description here

See my other answer for more additional info on V5 billing

https://mcmap.net/q/293096/-google-play-error-quot-error-while-retrieving-information-from-server-df-dferh-01-quot

Thou answered 8/9, 2022 at 14:1 Comment(2)
not have any offers.. i want migrated v4 to v6.. productDetails.subscriptionOfferDetails?.first()?.offerToken is it enough ?Rebak
i think in that case productDetails.getSubscriptionOfferDetails().size() should be 1, right?Thou
F
3

Example you have 2 subscriptions (2 products) like this

[
  ProductDetails{
    parsedJson={
      "productId": "...",
      "subscriptionOfferDetails": [
        {
          "offerIdToken": "...token_1...",
          "pricingPhases": [
            {
              "priceAmountMicros": 631000000000,
              "priceCurrencyCode": "VND",
              "formattedPrice": "₫631,000",
              "billingPeriod": "P6M",
              
            }
          ]
        }
      ]
    }
  },
  ProductDetails{
    parsedJson={
      "productId": "...",
      "subscriptionOfferDetails": [
        {
          "offerIdToken": "...token_2...",
          "pricingPhases": [
            {
              "priceAmountMicros": 0,
              "priceCurrencyCode": "VND",
              "formattedPrice": "Free",
              "billingPeriod": "P1M",
              "recurrenceMode": 2,
              "billingCycleCount": 1
            },
            {
              "priceAmountMicros": 112000000000,
              "priceCurrencyCode": "VND",
              "formattedPrice": "₫112,000",
              "billingPeriod": "P6M",
              
            }
          ],
          {
            "offerIdToken": "...token_3...",
            "pricingPhases": [
              {
                "priceAmountMicros": 631000000000,
                "priceCurrencyCode": "VND",
                "formattedPrice": "₫631,000",
                "billingPeriod": "P6M",
              }
            ]
          }
        }
      ]
    }
  }
]

Example to buy the 1st plan (with 1 month free trial) on 2nd subscription (ProductDetails)

val productDetails2 = ...
val offerToken = "...token_2..."
// val offerToken = productDetails2.subscriptionOfferDetails.get(0).offerToken
// in json response, it name is offerIdToken but after parse it's offerToken

val productDetailsParamsList =
    listOf(
        BillingFlowParams.ProductDetailsParams.newBuilder()
            .setProductDetails(productDetails2)
            .setOfferToken(offerToken)
            .build()
    )
val billingFlowParams = BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .build()

billingClient.launchBillingFlow(this, billingFlowParams)
Forde answered 16/6, 2022 at 4:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.