> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.qonversion.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Android SDK 6.x to 7.x migration guide

> We've upgraded the Google Play Billing Library dependency to version 6 in this release, which has led to major changes in the product and subscription management parts of our SDK. These are described below.

## Upgrading version

Increase the dependency version in your app *build.gradle* file to upgrade your Qonversion SDK to the latest version

<CodeGroup>
  ```groovy build.gradle theme={null}
  dependencies {    
       implementation 'io.qonversion.android.sdk:sdk:7.+'
  }
  ```
</CodeGroup>

## Product updates

### Qonversion and Google Play product link changes

Google Play has recently upgraded the structure of their subscription products. We've written about it [in our blog](https://qonversion.io/blog/google-play-billing-library-5-0/). In short, they combined the same subscriptions with different durations into a single subscription with different base plans. In addition, they announced different kinds of offers to base plans, including free trials or introductory prices. In this release, we begin to support those changes.

Previously Qonversion **subscription** products required a Google Play subscription identifier. Now you can also set a specific **base plan** for the subscription. Different base plans of the same subscription can be linked to different Qonversion products. Let's have a look at an example.

Let's say you sell monthly and annual subscriptions in your app, both on Android and iOS. With the previous Qonversion SDK versions, you would specify two Qonversion products (`premium_monthly` and `premium_annual`), two App Store products (`premium_monthly_ios` and `premium_annual_ios`), and two Google Play products (`premium_monthly_android` and `premium_annual_android`). Then you would link those store products to Qonversion products as follows:

`premium_monthly` - `premium_monthly_ios` and `premium_monthly_android`,

`premium_annual` - `premium_annual_ios` and `premium_annual_android`.

With the new Google Play Subscriptions structure, you can create only one subscription for Android - `premium_android` and two base plans for it (`monthly` and `annual`). With this done, you can now use a single subscription for both Qonversion products as follows:

`premium_monthly` - `premium_monthly_ios` and `premium_android` with `monthly` base plan,

`premium_annual` - `premium_annual_ios` and `premium_android` with `annual` base plan.

### Store details for the `QProduct` class

Speaking of the SDK side - the first big part of the changes is the addition of the new `basePlanId` field to `QProduct` which can be set to the product via Qonversion Dashboard.

We have deprecated the `QProduct.skuDetails` field, because `SkuDetails` contain information only for backward compatible base plans and are now deprecated in the Google Play Billing Library. Instead, we have added the new `storeDetails` field of type `QProductStoreDetails`, which contains all the store information for the Google Play Product. You can find the specifications of that class [on this page](google-play-product-details).

If `basePlanId` is not specified for a product, it means one of the following:

* it is a one-time (in-app) product that can not have any base plans,
* it is a product that was not updated in the Qonversion dashboard after this version was released.

In the case of the in-app product, both `skuDetails` and `storeDetails` fields will contain information about that in-app. But in the second case, when there is a subscription product without a specified base plan, the `skuDetails` field will contain information about the **backward compatible** base plan, while the `storeDetails` field will only contain common subscription information without base-plan-specific data. It means that you should start using `storeDetails` field for base-plan-specific data (like price, duration, and so on) for subscription products only if you've specified their base plan IDs in Qonversion product settings.

### The other `QProduct` fields changes

Along with the above changes, we have changed the `type` field and removed the `duration` and `trialDuration` fields from the product class. The `type` and `duration` were previously being set via the dashboard, and the `trialDuration` was calculated from the store details and was represented as an enumeration with several common durations. Now, the product `type` is calculated from the store details. We've also added the `Intro` value to `QProductType` to separate `trial` and `intro` products. An `Unknown` value was also added for the cases where we are unable to determine the product type. The `duration` and `trialDuration` fields were replaced with `subscriptionPeriod` and `trialPeriod`. Both properties are of type `QSubscriptionPeriod` and the values are also calculated from the store details.

The last thing to note is that we've also changed the `prettyPrice` field calculation. Earlier it was calculated from `skuDetails`, while now we first try to use `storeDetails` if possible and only then fall back to `skuDetails`.

### `QProduct` updates summary

Below is the shortened summary of the `QProduct` changes:

* new `basePlanId` field, specifying concrete subscription base plan, added,
* `skuDetails` field deprecated,
* new `storeDetails` field, containing information about Google Play product, added;
* the `type` field is now calculated based on store details, instead of the value set via the Qonversion dashboard. The `Intro` and `Unknown` values were added to `QProductType` to separate cases of trial and intro products and also the case when we are unable to determine the product type;
* the `duration` and `trialDuration` fields were replaced with `subscriptionPeriod` and `trialPeriod` fields of type `QSubscriptionPeriod` with the values calculated from the store details;
* the `prettyPrice` field now prefers `storeDetails` to get the price from, and only then - `skuDetails`.

## Purchase flow updates

In this release, we have changed the `purchase` and `updatePurchase` methods signatures. Previously there were several methods for different sets of arguments. Now we've arranged all those properties into classes - `QPurchaseModel` and `QPurchaseUpdateModel`, that should be instantiated and provided to the single `purchase` or `updatePurchase` method.

You can create instances of those classes either manually or by using the utility functions `toPurchaseModel` and `toPurchaseUpdateModel` added to the `QProduct` class.

Below is an example of how the `purchase` flow has changed:

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Old
  Qonversion.shared.purchase(this, product, callback = object: QonversionEntitlementsCallback {...})

  // New
  val purchaseModel = product.toPurchaseModel()
  Qonversion.shared.purchase(this, purchaseModel, callback = object: QonversionEntitlementsCallback {...})
  ```

  ```java Java theme={null}
  // Old
  Qonversion.getSharedInstance().purchase(this, product, new QonversionEntitlementsCallback() {...});

  // New
  final QPurchaseModel purchaseModel = product.toPurchaseModel();
  Qonversion.getSharedInstance().purchase(this, purchaseModel, new QonversionEntitlementsCallback() {...});
  ```
</CodeGroup>

And an `updatePurchase` flow example:

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Old
  Qonversion.shared.updatePurchase(this, product, "oldProductId", callback = object: QonversionEntitlementsCallback {...})

  // New
  val purchaseUpdateModel = product.toPurchaseUpdateModel("oldProductId")
  Qonversion.shared.updatePurchase(this, purchaseUpdateModel, callback = object: QonversionEntitlementsCallback {...})
  ```

  ```java Java theme={null}
  // Old
  Qonversion.getSharedInstance().updatePurchase(this, newProduct, "oldProductId", new QonversionEntitlementsCallback() {...});

  // New
  final QPurchaseUpdateModel purchaseUpdateModel = newProduct.toPurchaseUpdateModel("oldProductId");
  Qonversion.getSharedInstance().updatePurchase(this, purchaseUpdateModel, new QonversionEntitlementsCallback() {...});
  ```
</CodeGroup>

If you were using only product identifiers, you can create purchase models manually as follows:

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Old
  Qonversion.shared.purchase(this, "productId", callback = object: QonversionEntitlementsCallback {...})

  // New
  val purchaseModel = QPurchaseModel("productId")
  Qonversion.shared.purchase(this, purchaseModel, callback = object: QonversionEntitlementsCallback {...})
  ```

  ```java Java theme={null}
  // Old
  Qonversion.getSharedInstance().purchase(this, "productId", new QonversionEntitlementsCallback() {...});

  // New
  final QPurchaseModel purchaseModel = new QPurchaseModel("productId");
  Qonversion.getSharedInstance().purchase(this, purchaseModel, new QonversionEntitlementsCallback() {...});
  ```
</CodeGroup>

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Old
  Qonversion.shared.updatePurchase(this, "newProductId", "oldProductId", callback = object: QonversionEntitlementsCallback {...})

  // New
  val purchaseUpdateModel = QPurchaseUpdateModel("newProductId", "oldProductId")
  Qonversion.shared.updatePurchase(this, purchaseUpdateModel, callback = object: QonversionEntitlementsCallback {...})
  ```

  ```java Java theme={null}
  // Old
  Qonversion.getSharedInstance().updatePurchase(this, "newProductId", "oldProductId", new QonversionEntitlementsCallback() {...});

  // New
  final QPurchaseUpdateModel purchaseUpdateModel = new QPurchaseUpdateModel("newProductId", "oldProductId");
  Qonversion.getSharedInstance().updatePurchase(this, purchaseUpdateModel, new QonversionEntitlementsCallback() {...});
  ```
</CodeGroup>

If necessary, you can provide a specific offer identifier for subscription purchase.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Specifying offer via the `toPurchaseModel` method:
  val productOfferDetails = ... // Choose an offer from `storeDetails`
  val purchaseModel = product.toPurchaseModel(productOfferDetails)

  // Specifying offer ID via the `toPurchaseModel` method:
  val purchaseModel = product.toPurchaseModel("offer_id")

  // Specifying offer ID via the constructor:
  val purchaseModel = QPurchaseModel("productId", "offer_id")
  val purchaseUpdateModel = QPurchaseUpdateModel("newProductId", "oldProductId", "offer_id")

  // Specifying offer ID after the purchase model creation:
  purchaseModel.offerId = "offer_id"
  ```

  ```java Java theme={null}
  // Specifying offer via the `toPurchaseModel` method:
  final QProductOfferDetails productOfferDetails = ...; // Choose an offer from `storeDetails`
  final QPurchaseModel purchaseModel = product.toPurchaseModel(productOfferDetails);

  // Specifying offer ID via the `toPurchaseModel` method:
  final QPurchaseModel purchaseModel = product.toPurchaseModel("offer_id");

  // Specifying offer ID via the constructor:
  final QPurchaseModel purchaseModel = new QPurchaseModel("productId", "offer_id");
  final QPurchaseUpdateModel purchaseUpdateModel = new QPurchaseUpdateModel("newProductId", "oldProductId", "offer_id");

  // Specifying offer ID after the purchase model creation:
  purchaseModel.setOfferId("offer_id");
  ```
</CodeGroup>

If provided, we will try to find and purchase the offer with the specified ID for the requested Qonversion product. If there is no offer with the specified ID, an error will be returned. If no offer ID is provided for the subscription purchase of Qonversion product with a specified base plan ID, then we will choose the most profitable offer for the client from all the available offers. We calculate the cheapest price for the client by comparing all the trial or intro phases and the base plan. For old Qonversion products (where the base plan ID is not specified), as well as for in-app products, the offer ID is ignored.

You can also remove any intro/trial offer from the purchase (use only a bare base plan). For that purpose, you should call `removeOffer` method of purchase model:

<CodeGroup>
  ```kotlin Kotlin theme={null}
  purchaseModel.removeOffer()
  ```

  ```java Java theme={null}
  purchaseModel.removeOffer();
  ```
</CodeGroup>

## The other changes

* Google Play Billing Library version was upgraded from 6.0.1 to the latest 6.1.0;
* The minimal supported SDK version was upgraded from 16 to 19, the Kotlin version was also upgraded from 1.6 to 1.8;
* The `checkTrialIntroEligibility` method was improved and now detects the eligibility based on store details;
* `QonversionErrorCode.SkuDetailsError` was removed;
* The `QProductDuration` and `QTrialDuration` classes were removed;
* The previously deprecated method `contextForScreenIntent` was removed from `AutomationsDelegate`.

***

[\[Jan 2024\] Migration guide. Google Play Billing Library 6.](qonversion-sdk-major-version-copy)

[Flutter SDK 7.x to 8.x migration guide](flutter-8-migration-guide)
