Skip to main content

Release 6.3.0

· 6 min read
Hyo
Maintainer of flutter_inapp_purchase & expo-iap

We're excited to announce the release of flutter_inapp_purchase 6.3.0! This version brings significant improvements to OpenIAP specification compliance, enhanced type safety, critical bug fixes, and a completely reorganized test suite—all while maintaining full backward compatibility.

What's New in 6.3.0​

Critical Bug Fixes​

Android Purchase State Mapping Fix (#524)​

Fixed a critical bug where Android purchase states were incorrectly mapped, potentially causing transactions to be misinterpreted:

Before (Incorrect):

  • 0 → PURCHASED ❌
  • 1 → PENDING ❌

After (Correct):

  • 0 → UNSPECIFIED_STATE ✅
  • 1 → PURCHASED ✅
  • 2 → PENDING ✅

This fix aligns with the official Google Play Billing documentation and prevents misinterpreting UNSPECIFIED_STATE as a completed purchase.

Deprecated Methods​

The following methods are now deprecated in favor of the unified fetchProducts API:

// ✅ Unified Product API
final inAppResult = await iap.fetchProducts(
ProductRequest(
skus: productIds,
type: ProductQueryType.InApp,
),
);
final products = inAppResult.inAppProducts();

final subResult = await iap.fetchProducts(
ProductRequest(
skus: subscriptionIds,
type: ProductQueryType.Subs,
),
);
final subscriptions = subResult.subscriptionProducts();

Enhanced OpenIAP Field Support​

One of the biggest improvements in 6.3.0 is comprehensive field mapping following the OpenIAP specification. We've added extensive support for platform-specific fields that were previously unavailable.

iOS StoreKit 2 Integration​

Products and subscriptions now include comprehensive iOS fields:

final products = await FlutterInappPurchase.instance.fetchProducts(
RequestProductsParams(productIds: ['premium_monthly']),
);

final product = products.first;
print('Display Name: ${product.displayName}');
print('Family Shareable: ${product.isFamilyShareable}');
print('JSON Representation: ${product.jsonRepresentation}');

// Access subscription-specific info
if (product.subscription != null) {
print('Subscription Group: ${product.subscription!.subscriptionGroupId}');
print('Promotional Offers: ${product.promotionalOfferIdsIOS}');
}

Purchase objects now include StoreKit 2 verification and metadata:

FlutterInappPurchase.instance.purchaseUpdatedListener.listen((purchase) {
// Enhanced verification data
print('Verification Result: ${purchase.verificationResultIOS}');
print('Environment: ${purchase.environmentIOS}'); // "Sandbox" | "Production"
print('Expiration Date: ${purchase.expirationDateIOS}');

// JWS token for server validation
if (purchase.purchaseToken != null) {
// Send to your server for App Store validation
validateWithAppStore(purchase.purchaseToken!);
}
});

Android Google Play Enhanced Fields​

Android purchases now include comprehensive Google Play Billing fields:

// Enhanced Android purchase validation
if (purchase.platform == IapPlatform.android) {
print('Order ID: ${purchase.orderIdAndroid}');
print('Package Name: ${purchase.packageNameAndroid}');
print('Signature: ${purchase.signatureAndroid}');
print('Acknowledged: ${purchase.acknowledgedAndroid}');

// Use for server-side validation
final validationData = {
'purchaseToken': purchase.purchaseToken,
'signature': purchase.signatureAndroid,
'packageName': purchase.packageNameAndroid,
};
await validateWithGooglePlay(validationData);
}

Improved Type Safety & Reliability​

We've significantly improved the plugin's type safety and error handling:

Better JSON Parsing​

Fixed critical type casting issues that could cause runtime errors:

// Before: Could throw casting exceptions
// Map<Object?, Object?> causing runtime errors

// After: Safe conversion with proper error handling
Map<String, dynamic>.from(item as Map)

Enhanced Subscription Detection​

Improved subscription detection logic across platforms with correct state mapping.

Test Suite Overhaul​

We've completely reorganized our test suite for better maintainability and coverage:

Organized by Business Flows​

  • Purchase Flow Tests (test/purchase_flow_test.dart): General purchase operations, error handling, and platform-specific behaviors
  • Subscription Flow Tests (test/subscription_flow_test.dart): Subscription management, active subscription detection, and lifecycle operations
  • Available Purchases Tests (test/available_purchases_test.dart): Purchase history, restoration, and transaction management

Improved Coverage​

  • Test coverage improved from 26% to 28.2%
  • All 95 tests now pass consistently
  • Better mock data consistency and more reliable assertions

Migration Guide​

Migration is Seamless​

The best part? No breaking changes! Version 6.3.0 is fully backward compatible:

// Your existing code continues to work unchanged
final iap = FlutterInappPurchase.instance;
await iap.initConnection();

// Use the new unified API (recommended)
final products = await iap.fetchProducts(
RequestProductsParams(
productIds: ['your_product_id'],
type: PurchaseType.inapp, // or PurchaseType.subs
),
);

await iap.requestPurchase(
request: RequestPurchase(
ios: RequestPurchaseIOS(sku: 'your_product_id'),
android: RequestPurchaseAndroid(skus: ['your_product_id']),
),
type: PurchaseType.inapp,
);

Simply update your pubspec.yaml:

dependencies:
flutter_inapp_purchase: ^6.3.0

Optional - Use New Fields​

You can now access additional platform-specific fields:

Accessing iOS-Specific Product Information​

// Before (still works)
final products = await FlutterInappPurchase.instance.fetchProducts(
RequestProductsParams(productIds: ['premium_monthly']),
);
print('Price: ${products.first.price}');

// After (enhanced with new fields)
final product = products.first;
print('Price: ${product.price}');
print('Display Name: ${product.displayName}'); // New
print('Family Shareable: ${product.isFamilyShareable}'); // New

// Access subscription info
if (product.subscription != null) {
print('Subscription Group: ${product.subscription!.subscriptionGroupId}');
}

Accessing Enhanced Purchase Information​

// Purchase handling with new fields
FlutterInappPurchase.instance.purchaseUpdatedListener.listen((purchase) {
print('Product ID: ${purchase.productId}');
print('Transaction ID: ${purchase.transactionId}');

// New iOS fields
if (purchase.verificationResultIOS != null) {
print('Verification: ${purchase.verificationResultIOS}');
}
if (purchase.environmentIOS != null) {
print('Environment: ${purchase.environmentIOS}'); // "Sandbox" | "Production"
}

// New Android fields
if (purchase.signatureAndroid != null) {
print('Signature: ${purchase.signatureAndroid}');
}
});

Enhanced Server-Side Validation​

The new fields enable more robust server-side validation:

Future<bool> validatePurchase(Purchase purchase) async {
final validationData = {
'transactionId': purchase.transactionId,
'productId': purchase.productId,
'purchaseToken': purchase.purchaseToken,
};

if (purchase.platform == IapPlatform.ios) {
// Use StoreKit 2 JWS token
validationData['jwsRepresentation'] = purchase.purchaseToken;
validationData['environment'] = purchase.environmentIOS;

return await validateWithAppStore(validationData);
} else {
// Use Google Play signature validation
validationData['signature'] = purchase.signatureAndroid;
validationData['packageName'] = purchase.packageNameAndroid;

return await validateWithGooglePlay(validationData);
}
}

Technical Improvements​

Under the Hood​

  • Enhanced JSON serialization/deserialization with better error handling
  • Improved mock data consistency across all test files
  • Better error messages and debugging information
  • Standardized field naming following OpenIAP conventions
  • Fixed critical Android purchase state mapping

Developer Experience​

  • Comprehensive test coverage for all business flows
  • Better documentation with practical examples
  • Type-safe APIs with improved null safety
  • Consistent behavior across iOS and Android platforms
  • Unified API with deprecated methods properly marked

Testing Improvements​

Better Test Organization​

If you were running tests before, you'll notice improved organization:

# Tests are now organized by flow
flutter test test/purchase_flow_test.dart # General purchases
flutter test test/subscription_flow_test.dart # Subscriptions
flutter test test/available_purchases_test.dart # Purchase history

Enhanced Test Coverage​

  • Test coverage improved from 26% to 28.2%
  • All 95 tests now pass consistently
  • Better mock data and more reliable assertions

Why Upgrade?​

  1. Critical Bug Fix: Android purchase state mapping now correctly interprets transaction states
  2. Enhanced OpenIAP Compliance: Access to comprehensive platform-specific fields
  3. Better Reliability: Improved type safety and error handling
  4. Future-Proof: Foundation for upcoming OpenIAP features
  5. Better Testing: More comprehensive and reliable test suite
  6. No Breaking Changes: Seamless upgrade experience

Troubleshooting​

Since 6.3.0 is fully backward compatible, you shouldn't encounter any breaking changes. If you do experience issues:

  1. Clean and rebuild:

    flutter clean
    flutter pub get
    flutter run
  2. Check for proper imports:

    import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
  3. Verify platform support:

    • iOS: Requires iOS 11.0+ (StoreKit 2 features need iOS 15.0+)
    • Android: Requires API level 19+ with Google Play Billing Library
  4. Update deprecated method calls: Use fetchProducts() for both in-app items and subscriptions

Resources​

Community​

This release wouldn't be possible without our amazing community. Special thanks to all contributors, testers, and users who provided feedback and helped improve the plugin. Special recognition to @quancr258 for reporting the critical Android purchase state mapping issue (#524).


What's Next?​

We're continuing to work on expanding OpenIAP compliance and improving the developer experience. Stay tuned for future releases!

Happy coding with flutter_inapp_purchase 6.3.0!


+Published on August 19, 2025 by the flutter_inapp_purchase team