NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #3981 most downloaded on pub.dev
In App Purchase plugin for flutter. This project has been forked by react-native-iap and we are willing to share same experience with that on react-native.
Last release 5 days ago
30 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
3 versions withdrawn
withdrawn after publishing
8 years old
235 releases · first in 2018
Parameter naming: RequestPurchaseProps.inApp() and RequestPurchaseProps.subs() now use apple/google fields instead of ios/android
Parameter naming: RequestPurchaseProps.inApp() and RequestPurchaseProps.subs() now use apple/google fields instead of ios/android
// Before (8.1.x)
RequestPurchaseProps.inApp((
ios: RequestPurchaseIosProps(sku: 'product_id'),
android: RequestPurchaseAndroidProps(skus: ['product_id']),
))
// After (8.2.0)
RequestPurchaseProps.inApp((
apple: RequestPurchaseIosProps(sku: 'product_id'),
google: RequestPurchaseAndroidProps(skus: ['product_id']),
useAlternativeBilling: null,
))
AlternativeBillingModeAndroid: Use BillingProgramAndroid instead
AlternativeBillingModeAndroid.alternativeOnly -> BillingProgramAndroid.ExternalOfferAlternativeBillingModeAndroid.userChoice -> BillingProgramAndroid.UserChoiceBillingalternativeBillingModeAndroid parameter: Use enableBillingProgramAndroid in initConnection() instead
openiap-gql: 1.3.10 -> 1.3.11One column per quarter.
External Payments Program (Android 8.3.0+, Japan Only): Support for Google Play Billing Library 8.3.0's External Payments program
External Payments Program (Android 8.3.0+, Japan Only): Support for Google Play Billing Library 8.3.0's External Payments program
BillingProgramAndroid.ExternalPayments billing program typeDeveloperBillingOptionParamsAndroid to configure external payment option in purchase flowDeveloperBillingLaunchModeAndroid enum for how to launch the external payment linkDeveloperProvidedBillingDetailsAndroid type containing externalTransactionToken when user selects developer billingdeveloperProvidedBillingAndroid stream for listening to developer billing selection eventsdeveloperBillingOption field in RequestPurchaseAndroidProps and RequestSubscriptionAndroidProps// Listen for developer billing selection
iap.developerProvidedBillingAndroid.listen((details) {
// User selected developer billing
// Report transaction to Google within 24 hours using details.externalTransactionToken
print('External transaction token: ${details.externalTransactionToken}');
});
// Request purchase with external payments option
await iap.requestPurchaseWithBuilder(
build: (builder) {
builder.google.skus = ['product_id'];
builder.google.developerBillingOption = DeveloperBillingOptionParamsAndroid(
billingProgram: BillingProgramAndroid.ExternalPayments,
launchMode: DeveloperBillingLaunchModeAndroid.LaunchInExternalBrowserOrApp,
linkUri: 'https://example.com/checkout',
);
builder.type = ProductQueryType.InApp;
},
);
New Event: IapEvent.DeveloperProvidedBillingAndroid - Fired when user selects developer billing in External Payments flow
enableBillingProgramAndroid in InitConnectionConfig: Enable a specific billing program during connection initialization
// Enable External Payments during connection
await iap.initConnection(
enableBillingProgramAndroid: BillingProgramAndroid.ExternalPayments,
);
This provides a cleaner alternative to calling enableBillingProgram() separately before initConnection().
openiap-gql: 1.3.8 -> 1.3.10openiap-google: 1.3.16 -> 1.3.19openiap-apple: 1.3.7 -> 1.3.8openiap-google: 1.3.15 -> 1.3.16
openiap-google: 1.3.15 -> 1.3.16android field is now deprecated; use google instead
Advanced Commerce Data (iOS 15+): Support for StoreKit 2's Product.PurchaseOption.custom API
advancedCommerceData field in RequestPurchaseIosProps and RequestSubscriptionIosPropsawait iap.requestPurchaseWithBuilder(
build: (builder) {
builder.ios.sku = 'com.example.premium';
builder.ios.advancedCommerceData = 'campaign_summer_2025';
builder.type = ProductQueryType.InApp;
},
);
google field support (Android): New google field in request parameters with android fallback
android field is now deprecated; use google insteadrequestPurchaseOnPromotedProductIOS(): Use purchasePromoted stream + requestPurchase() instead
// Recommended approach
iap.purchasePromoted.listen((productId) async {
if (productId != null) {
await iap.requestPurchaseWithBuilder(
build: (builder) {
builder.ios.sku = productId;
builder.type = ProductQueryType.InApp;
},
);
}
});
openiap-apple: 1.3.5 -> 1.3.7openiap-google: 1.3.14 -> 1.3.16openiap-gql: 1.3.5 -> 1.3.8`verifyPurchase` and `validateReceipt` API changed: Now uses platform-specific options instead of deprecated sku and androidOptions parameters
oneTimePurchaseOfferDetailsAndroid is now an array: Changed from ProductAndroidOneTimePurchaseOfferDetail? to List<ProductAndroidOneTimePurchaseOfferDetail>? 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;
verifyPurchase and validateReceipt API changed: Now uses platform-specific options instead of deprecated sku and androidOptions parameters
// Before (v7.x)
final result = await iap.verifyPurchase(sku: 'product_id');
final result = await iap.verifyPurchase(
sku: 'product_id',
androidOptions: VerifyPurchaseAndroidOptions(...),
);
// After (v8.x) - iOS
final result = await iap.verifyPurchase(
apple: VerifyPurchaseAppleOptions(sku: 'product_id'),
);
// After (v8.x) - Android
final result = await iap.verifyPurchase(
google: VerifyPurchaseGoogleOptions(
sku: 'product_id',
accessToken: 'your-oauth-token', // From your backend
packageName: 'com.your.app',
purchaseToken: purchase.purchaseToken,
),
);
Billing Programs API (Android 8.2.0+): Support for external billing programs
isBillingProgramAvailableAndroid() - Check if a billing program is availablecreateBillingProgramReportingDetailsAndroid() - Get external transaction token for reportinglaunchExternalLinkAndroid() - Launch external link for billing programs// Check availability
final result = await iap.isBillingProgramAvailableAndroid(
BillingProgramAndroid.ExternalOffer,
);
if (result.isAvailable) {
// Launch external link
await iap.launchExternalLinkAndroid(
LaunchExternalLinkParamsAndroid(
billingProgram: BillingProgramAndroid.ExternalOffer,
launchMode: ExternalLinkLaunchModeAndroid.LaunchInExternalBrowserOrApp,
linkType: ExternalLinkTypeAndroid.LinkToDigitalContentOffer,
linkUri: 'https://your-payment-site.com/purchase',
),
);
// Get reporting token
final details = await iap.createBillingProgramReportingDetailsAndroid(
BillingProgramAndroid.ExternalOffer,
);
// Send details.externalTransactionToken to your server
}
One-Time Product Discounts (Android 8.0+): New fields in ProductAndroidOneTimePurchaseOfferDetail
offerId - Unique offer identifierfullPriceMicros - Full (non-discounted) pricediscountDisplayInfo - Discount percentage and amountlimitedQuantityInfo - Maximum and remaining quantityvalidTimeWindow - Offer validity periodofferTags - List of offer tagsofferToken - Token for purchase requestspreorderDetailsAndroid - Pre-order release dates (Android 8.0+)rentalDetailsAndroid - Rental period information (Android 8.0+)Purchase Suspension Status (Android 8.1.0+): New isSuspendedAndroid field in PurchaseAndroid
for (final purchase in purchases) {
if (purchase is PurchaseAndroid && purchase.isSuspendedAndroid == true) {
// Subscription suspended - do not grant access
// Direct user to fix payment method
}
}
checkAlternativeBillingAvailabilityAndroid() - Use isBillingProgramAvailableAndroid(BillingProgramAndroid.ExternalOffer) insteadshowAlternativeBillingDialogAndroid() - Use launchExternalLinkAndroid() insteadcreateAlternativeBillingTokenAndroid() - Use createBillingProgramReportingDetailsAndroid(BillingProgramAndroid.ExternalOffer) insteaddart:io import causing web build failures
dart:io Platform with defaultTargetPlatform from Flutter foundationkIsWeb guards to prevent native API calls on webopeniap-apple: 1.3.0 → 1.3.5openiap-google: 1.3.12 → 1.3.14openiap-gql: 1.3.2 → 1.3.5See Migration from v7 for detailed upgrade instructions.
feat: Add store field to Purchase types (deprecates platform)
IapStore enum for unified store identification (apple, google, horizon, unknown)store field to Purchase types (deprecates platform)apple/google keys in request parameters (alongside legacy ios/android)feat: Add verifyPurchaseWithProvider for IAPKit integration
verifyPurchaseWithProvider for IAPKit integration
VerificationMethod option: ignore, local, iapkit_Map<Object?, Object?> cast errors on iOS 26
normalizeDynamicMap for recursive map conversionchore(deps): Update openiap-versions
chore(deps): Update openiap-versions
{
"apple": "1.2.38"
}
chore(deps): Update openiap-versions
chore(deps): Update openiap-versions
{
"google": "1.3.7",
"apple": "1.2.38"
}
chore(deps): Update openiap-versions
chore(deps): Update openiap-versions
{
"google": "1.3.6",
"apple": "1.2.36"
}
feat: Add macOS platform support
chore(deps): openiap-apple@1.2.34
`json { "gql": "1.2.5", "google": "1.3.5", "apple": "1.2.32" } `
Update openiap-versions.
{
"gql": "1.2.5",
"google": "1.3.5",
"apple": "1.2.32"
}
fix(android): Prevent incomplete product data on repeated fetchProducts calls
fetchProducts calls
displayPrice and other fields were missing on subsequent calls:::warning Migration Required for v7.1.14+
Due to product flavor support added in v7.1.13, apps using Google Play must add platform dimension configuration to avoid build errors. Add to android/app/build.gradle:
android {
defaultConfig {
missingDimensionStrategy 'platform', 'play'
}
}
See Android Setup Guide for details. :::
feat: Add Horizon OS support for Meta Quest devices
openiap-google-horizon dependency for Meta Quest Platform SDKmissingDimensionStrategy 'platform', 'play' to their build.gradleintroductoryPricePaymentModeIOS is now required (non-nullable) in ProductSubscriptionIOS
PaymentModeIOS? to PaymentModeIOS (required field)PaymentModeIOS.Empty when not provided_parsePaymentMode helper to return PaymentModeIOS.Empty instead of nullintroductoryPricePaymentModeIOS: PaymentModeIOS.Empty when creating ProductSubscriptionIOS instances manually`json { "apple": "1.2.25", "google": "1.3.1", "gql": "1.2.2" } `
Update openiap-versions.
{
"apple": "1.2.25",
"google": "1.3.1",
"gql": "1.2.2"
}
fix: improve subscription state handling
fix: handle string timestamp in DiscountOfferInputIOS
chore(deps): openiap-apple@1.2.18
fix(ios): corrected transactionReason detection for re-purchased subscriptions by upgrading openiap-apple to `1.2.18` - Fixed an issue where previousl
1.2.18 - Fixed an issue where previously cancelled subscriptions that were purchased again were incorrectly marked as RENEWAL instead of PURCHASE. Now uses Apple's transactionReason from JSON representation for accurate transaction type detection.Accidental release with no changes.
Resolve issue like react-native-iap issue #3054 by upgrading openiap-apple to 1.2.17.
1.2.17.Fixed missing upgrade of openiap-apple module to 1.2.14 in the previous release.
openiap-apple module to 1.2.14 in the previous release.Updated openiap-apple to 1.2.14, improving promotional offer error messages.
openiap-apple to 1.2.14, improving promotional offer error messages.Upgrade openiap-apple module to 1.2.13.
1.2.13.Upgrade openiap-apple module to 1.2.12.
1.2.12.Breaking: fetchProducts() now returns Future > instead of specific typed lists
fetchProducts() now returns Future<List<dynamic>> instead of specific typed lists
final List<Product> products = await iap.fetchProducts(skus: ['id'], type: ProductQueryType.InApp);final List<ProductSubscription> subscriptions = await iap.fetchProducts(skus: ['id'], type: ProductQueryType.Subs);.value or .products gettersFetchProductsResultAdd missing isEligibleForIntroOfferIOS method (Fixes #574)
isEligibleForIntroOfferIOS method (Fixes #574)Breaking: Removed deprecated iOS-specific methods
presentExternalPurchaseLinkIOS()userChoiceBillingAndroid for Android User Choice BillingcheckAlternativeBillingAvailabilityAndroid(), showAlternativeBillingDialogAndroid(), createAlternativeBillingTokenAndroid()fetchProducts() now uses named parameters instead of ProductRequest objectgetAvailablePurchases() now uses named parameters instead of PurchaseOptions objectfinishTransaction() simplified to accept Purchase object directlyvalidateReceiptIOS(), deepLinkToSubscriptions() now use named parametersRequestPurchaseProps.inApp() / .subs() factory methods removed (use constructor with type parameter)getAvailableItemsIOS() - Use getAvailablePurchases() insteadgetAppTransactionTypedIOS() - Use getAppTransactionIOS() insteadgetPurchaseHistoriesIOS() - Use getAvailablePurchases() with options instead_buildIosPurchasePayload to public utils for better code organizationNothing published for this version
Update OpenIAP google module to 1.2.10
1.2.10- Update readme
feat: fetchProducts with ProductQueryType.All #568
fix(android): openiap module version path
- fix(ios): Resolve #567
fix(ios): send error only once - prevent duplicate purchase error events on iOS
Full Changelog: https://github.com/hyochan/flutter_inapp_purchase/compare/6.8.2...6.8.3
fix: resolve type casting error with PurchaseOptions by @hyochan in
Full Changelog: https://github.com/hyochan/flutter_inapp_purchase/compare/6.8.1...6.8.2
chore(deps): openiap-apple@1.2.3 #562
migrate Flutter In-App Purchase fully into the OpenIAP ecosystem, aligning with openiap-apple@1.2.2, openiap-google@1.2.6, and openiap-gql@1.0.8.
openiap-apple@1.2.2, openiap-google@1.2.6, and openiap-gql@1.0.8.fetchProducts(ProductRequest(...)) with typed helpers and extend getAvailablePurchases() via PurchaseOptions; legacy getProducts, getSubscriptions, and getPurchaseHistories are removed.purchaseToken as the canonical receipt for server validation.refactor: align openiap-gql@1.0.6
openiap-google@1.1.12Follow-up fixes & refinements for 6.7.0
fix(android): honor subscription offerToken
openiap-google@1.1.11openiap-apple@1.1.12refactor: locally suppress legacy jwsRepresentation mapping and deprecated requestPurchase calls kept for backward compatibility.
product.id is always populated in fetchProducts() (fixes cases where id was empty on iOS). The parser now resolves id from the first non-empty of: productId → id → sku → productIdentifier (#550). In debug builds, logs which key was used.
withOpacity in example UI.PurchaseIOS (use super.expirationDateIOS).jwsRepresentation mapping and deprecated requestPurchase calls kept for backward compatibility.id is the primary identifier for Product/ProductSubscription. productId is kept for backward compatibility only (see Deprecated).fetchProducts(): Adds support for type: 'all'.
'all' through the native fetchProducts callinapp and subs, then merges resultsproductId on ProductCommon: Use id instead (will be removed in 6.6.0).Subscription type name: Use ProductSubscription instead (will be removed in 6.6.0). The alias keeps existing code working.ProductSubscription (alias of Subscription) for subscriptions internally.PurchasedItem → Purchase in current docs/examples.Android: Migrated native billing to openiap-google and simplified plugin with coroutines and connection gating.
fetchProducts() → use fetchProducts()purchaseAsync() → use requestPurchase()requestPurchaseAuto() → use requestPurchase()finalize() → use endConnection()deepLinkToSubscriptionsAndroid() → use platform UI links as documentedgetPurchaseHistories() → use getAvailablePurchases(PurchaseOptions(onlyIncludeActiveItemsIOS: false))Nothing published for this version
Recommend upgrading to 6.5.2. Prior 6.5.0–6.5.1 allowed older constraints; this release enforces exact 1.1.9 for stability. No breaking changes.
type 'double' is not a subtype of type 'String?'), fixes #547.openiap 1.1.9 (exact version) to avoid unexpected CocoaPods minor updates.iOS: bump OpenIAP Apple native module to openiap ~> 1.1.8 (no breaking changes)
openiap ~> 1.1.8 (no breaking changes)OpenIapError.defaultMessage (OpenIAP 1.1.8 consolidation)1.1.8; run cd example/ios && pod install to refresh lockfile.iOS: Retrieve expired subscriptions in StoreKit 2 sandbox
PurchaseOptions parameter to getAvailablePurchases() for OpenIAP complianceonlyIncludeActiveItemsIOS: false to include expired subscriptionsgetPurchaseHistories() → Use getAvailablePurchases() with options (removed in 6.6.0)BREAKING: Updated getAvailablePurchases() to support PurchaseOptions parameter (OpenIAP compliant)
getAvailablePurchases() to support PurchaseOptions parameter (OpenIAP compliant)
PurchaseOptions parameter for platform-specific configurationonlyIncludeActiveItemsIOS option (default: true) to control whether expired subscriptions are includedPurchaseOptions class with iOS-specific options:
alsoPublishToEventListenerIOS: Whether to also publish purchase events to the event listener when fetching available purchasesonlyIncludeActiveItemsIOS: Whether to only include active items (set to false to get expired subscriptions)getPurchaseHistoriesIOS() platform-specific method that retrieves all transactions including expired subscriptionsgetPurchaseHistories() - Use getAvailablePurchases(PurchaseOptions(onlyIncludeActiveItemsIOS: false)) instead (will be removed in 6.6.0)Transaction.all instead of Transaction.currentEntitlementsAndroid: Fixed FormatException when calling finishTransaction
iOS: Replace ISO8601DateFormatter with millisecond timestamps for date fields
expirationDateIOS and revocationDateIOS to use millisecond timestampsRemoved parsing of deprecated subscriptionOfferDetails field
subscriptionOfferDetailsAndroid field returning null (Fixes #534)
subscriptionOfferDetailsAndroid in subscription productssubscriptionOfferDetails fieldMap<dynamic, dynamic> inputsas Map<String, dynamic> casts in types.dartActiveSubscription Type: Implemented a dedicated ActiveSubscription type for subscription APIs to provide better type safety and clearer subscription
ActiveSubscription type for subscription APIs to provide better type safety and clearer subscription status information (#532)
getActiveSubscriptions() now returns List<ActiveSubscription> instead of List<SubscriptionPurchase>willExpireSoon and daysUntilExpirationIOSWe understand there have been several breaking changes recently. We sincerely apologize for any inconvenience. These changes are part of our effort to…
Simplified fetchProducts API: The fetchProducts method now accepts direct parameters instead of a wrapper object (Fixes #527)
// Before (6.3.x)
final products = await iap.fetchProducts(
RequestProductsParams(
skus: ['product_id'],
type: PurchaseType.inapp,
),
);
// After (6.4.0)
final products = await iap.fetchProducts(
skus: ['product_id'],
type: PurchaseType.inapp, // Optional, defaults to PurchaseType.inapp
);
RequestProductsParams classDSL-like Builder Pattern for Purchase Requests: Added a builder pattern API for more intuitive and type-safe purchase request construction
// New builder pattern approach
await iap.requestPurchaseWithBuilder(
build: (r) => r
..type = PurchaseType.inapp
..withIOS((i) => i
..sku = 'product_id'
..quantity = 1)
..withAndroid((a) => a
..skus = ['product_id']),
);
AndroidPurchaseState enum instead of hardcoded values (0, 1, 2)
The following deprecated items from v6.3.x have been removed in v6.4.0:
subscriptionOfferDetails field (use subscriptionOfferDetailsAndroid instead)prorationMode field (use replacementModeAndroid instead)AndroidProrationMode typedef (use AndroidReplacementMode instead)We understand there have been several breaking changes recently. We sincerely apologize for any inconvenience. These changes are part of our effort to quickly address the long maintenance gap and bring the library up to modern standards. With version 6.4.0, we believe the major restructuring is now complete, and the API should remain stable going forward.
Added comprehensive TODO comments for v6.4.0 deprecation cleanup
nameAndroid and oneTimePurchaseOfferDetailsAndroid fieldsdataAndroid field mapping from native Android data_platform.isAndroid and _platform.isIOS conditions for platform-specific fieldsiOS Purchase State Detection: Enhanced purchase state detection for iOS
transactionStateIOS is nullkDebugMode flagTest Product Cleanup: Removed deprecated android.test.purchased test product ID
_Map<String, dynamic> type casting issue that prevented subscriptions from loadingandroid.test.purchased test product ID
CRITICAL FIX: Android Purchase State Mapping: Fixed incorrect mapping of Android purchase states
PurchaseState.unspecifiedEnhanced OpenIAP Compliance: Extended OpenIAP specification support with comprehensive field mapping
displayName, displayPrice, isFamilyShareable, jsonRepresentation, discountsIOS, subscription info, and promotional offer fieldsoriginalPrice, originalPriceAmount, freeTrialPeriod, subscriptionOffersAndroid, and billing cycle informationverificationResultIOS, environmentIOS, expirationDateIOS, revocationDateIOS, and transaction metadataImproved Test Organization: Restructured test suite by business flows
Type Safety: Enhanced type casting and JSON parsing reliability
Map<Object?, Object?> to Map<String, dynamic> conversion issuesSubscription Management: Enhanced active subscription detection
Code Quality: Comprehensive test suite improvements
fetchProducts with PurchaseType.subs returned empty arrays
getItems method instead of unsupported getSubscriptionsNone - This version maintains full backward compatibility while extending functionality.
Deprecated platform-specific token fields in favor of unified approach
id field to Purchase class for standardized transaction identificationpurchaseToken field for cross-platform server validation
finishTransaction now accepts Purchase objects directlytransactionId and id fields in Android purchase responsesPurchase.fromJson()None - This version maintains backward compatibility.
API Cleanup: Removed all deprecated methods that were marked for removal in 6.0.0
initialize() - use initConnection() insteadcheckSubscribed() - implement custom logic with getAvailablePurchases()showInAppMessageAndroid() - no longer supportedmanageSubscription() - use deepLinkToSubscriptionsAndroid() insteadopenPlayStoreSubscriptions() - use deepLinkToSubscriptionsAndroid() insteadclearTransactionIOS() - no longer neededshowPromoCodesIOS() - use presentCodeRedemptionSheetIOS() insteadgetPromotedProductIOS() and requestPromotedProductIOS() - use standard purchase flowrequestProductWithOfferIOS() and requestPurchaseWithQuantityIOS() - use requestPurchase() with RequestPurchase objectconsumePurchaseAndroidLegacy() and validateReceiptAndroidLegacy() - use modern equivalentsdeepLinkToSubscriptionsAndroidLegacy() - use deepLinkToSubscriptionsAndroid()acknowledgePurchaseAndroid() - use finishTransaction() instead_requestPurchaseOld() internal methodIf you're upgrading from 6.0.x and were using any deprecated methods:
initialize() with initConnection()acknowledgePurchaseAndroid() with finishTransaction()requestPurchase() with proper RequestPurchase objects instead of platform-specific methodspresentCodeRedemptionSheetIOS() for promo codes on iOSYour coding agent can read these notes before it upgrades. Set up the MCP server →