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
}
}
Advanced Commerce Data (v8.1.0+)
New support for StoreKit 2's attribution data API on iOS 15+:
await iap.requestPurchaseWithBuilder(
build: (builder) {
builder.ios.sku = 'com.example.premium';
builder.ios.advancedCommerceData = 'campaign_summer_2025';
builder.type = ProductQueryType.InApp;
},
);
Use cases:
- Campaign attribution tracking
- Affiliate marketing integration
- Promotional code tracking
Promoted Products (v8.1.0+)
requestPurchaseOnPromotedProductIOS() is now deprecated. Use the purchasePromoted stream instead:
Before (deprecated):
await iap.requestPurchaseOnPromotedProductIOS();
After (recommended):
iap.purchasePromoted.listen((productId) async {
if (productId != null) {
await iap.requestPurchaseWithBuilder(
build: (builder) {
builder.ios.sku = productId;
builder.type = ProductQueryType.InApp;
},
);
}
});
google Field Support (v8.1.0+)
Android request parameters now support the google field (recommended) alongside the deprecated android field:
// types.dart - RequestPurchasePropsByPlatforms
RequestPurchasePropsByPlatforms(
google: RequestPurchaseAndroidProps(skus: ['sku']), // Recommended
// android: ... // Deprecated
);
Dependencies Update
Update your pubspec.yaml:
dependencies:
flutter_inapp_purchase: ^8.1.0
The plugin automatically uses:
openiap-apple: 1.3.7openiap-google: 1.3.16openiap-gql: 1.3.8
