Skip to main content

Version 6.3.0 - Enhanced OpenIAP Compliance & Better Testing

· 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 requestProducts API:

// ❌ Deprecated methods (still work but will be removed in next major version)
await iap.getProducts(productIds);
await iap.getSubscriptions(productIds);

// ✅ Use requestProducts instead
await iap.requestProducts(
RequestProductsParams(
productIds: productIds,
type: PurchaseType.inapp, // or PurchaseType.subs
),
);

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.requestProducts(
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.requestProducts(
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.requestProducts(
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: Replace getProducts() and getSubscriptions() with requestProducts()

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