Migration from v7
This guide helps you migrate from flutter_inapp_purchase v7.x to v8.0.
Breaking Changes
oneTimePurchaseOfferDetailsAndroid is now an array
The most significant breaking change is that oneTimePurchaseOfferDetailsAndroid changed from a single object to an array. This was necessary to support multiple discount offers per product (Google Play Billing 7.0+).
Before (v7.x):
final price = product.oneTimePurchaseOfferDetailsAndroid?.formattedPrice;
After (v8.x):
final offers = product.oneTimePurchaseOfferDetailsAndroid;
final price = offers?.isNotEmpty == true ? offers![0].formattedPrice : null;
// Or iterate through all offers
for (final offer in offers ?? []) {
print('Offer: ${offer.offerId ?? "default"}');
print('Price: ${offer.formattedPrice}');
// Check for discount info
if (offer.discountDisplayInfo != null) {
print('Discount: ${offer.discountDisplayInfo!.percentageDiscount}% off');
}
}
verifyPurchase API changed
The verification APIs now use platform-specific options objects instead of the deprecated sku and androidOptions parameters.
Before (v7.x):
// iOS
final result = await iap.verifyPurchase(sku: 'product_id');
// Android
final result = await iap.verifyPurchase(
sku: 'product_id',
androidOptions: VerifyPurchaseAndroidOptions(
accessToken: 'token',
packageName: 'com.your.app',
productToken: 'purchase_token',
),
);
After (v8.x):
// iOS - use apple options
final result = await iap.verifyPurchase(
apple: VerifyPurchaseAppleOptions(sku: 'product_id'),
);
// Android - use google options
final result = await iap.verifyPurchase(
google: VerifyPurchaseGoogleOptions(
sku: 'product_id',
accessToken: 'your-oauth-token', // From your backend
packageName: 'com.your.app',
purchaseToken: purchase.purchaseToken,
),
);
// Meta Horizon (Quest) - use horizon options
final result = await iap.verifyPurchase(
horizon: VerifyPurchaseHorizonOptions(
sku: 'product_id',
accessToken: 'your-meta-token',
userId: 'user_id',
),
);
Note: The same change applies to validateReceipt and validateReceiptIOS.
Deprecated APIs
Alternative Billing APIs
The Alternative Billing APIs are deprecated in favor of the new Billing Programs API:
| Deprecated | Replacement |
|---|---|
checkAlternativeBillingAvailabilityAndroid() | isBillingProgramAvailableAndroid(BillingProgramAndroid.ExternalOffer) |
showAlternativeBillingDialogAndroid() | launchExternalLinkAndroid() |
createAlternativeBillingTokenAndroid() | createBillingProgramReportingDetailsAndroid(BillingProgramAndroid.ExternalOffer) |
Before (v7.x):
final available = await iap.checkAlternativeBillingAvailabilityAndroid();
if (available) {
await iap.showAlternativeBillingDialogAndroid();
final token = await iap.createAlternativeBillingTokenAndroid();
}
After (v8.x):
final result = await iap.isBillingProgramAvailableAndroid(
BillingProgramAndroid.ExternalOffer,
);
if (result.isAvailable) {
await iap.launchExternalLinkAndroid(
LaunchExternalLinkParamsAndroid(
billingProgram: BillingProgramAndroid.ExternalOffer,
launchMode: ExternalLinkLaunchModeAndroid.LaunchInExternalBrowserOrApp,
linkType: ExternalLinkTypeAndroid.LinkToDigitalContentOffer,
linkUri: 'https://your-payment-site.com/purchase',
),
);
final details = await iap.createBillingProgramReportingDetailsAndroid(
BillingProgramAndroid.ExternalOffer,
);
// Use details.externalTransactionToken
}
New Features
Billing Programs API
The new Billing Programs API provides three methods:
isBillingProgramAvailableAndroid(program)- Check if a billing program is availablelaunchExternalLinkAndroid(params)- Launch external link for billing programscreateBillingProgramReportingDetailsAndroid(program)- Get external transaction token
See Billing Programs Guide for detailed usage.
One-Time Product Discount Fields
New fields are available in ProductAndroidOneTimePurchaseOfferDetail:
offerId- Unique offer identifierfullPriceMicros- Full (non-discounted) pricediscountDisplayInfo- ContainspercentageDiscountanddiscountAmountlimitedQuantityInfo- Maximum and remaining quantityvalidTimeWindow- Offer start and end timesofferTags- List of tags for the offerofferToken- Token for purchase requestspreorderDetailsAndroid- Pre-order release dates (Android 8.0+)rentalDetailsAndroid- Rental period info (Android 8.0+)
Purchase Suspension Status
Check if a subscription is suspended due to payment issues:
final purchases = await iap.getAvailablePurchases();
for (final purchase in purchases) {
if (purchase is PurchaseAndroid && purchase.isSuspendedAndroid == true) {
// Do NOT grant entitlements for suspended subscriptions
// Direct user to fix payment method
}
}
Dependencies Update
Update your pubspec.yaml:
dependencies:
flutter_inapp_purchase: ^8.0.0
The plugin automatically uses:
openiap-apple: 1.3.2openiap-google: 1.3.14openiap-gql: 1.3.4
