easy_iap 0.2.0 copy "easy_iap: ^0.2.0" to clipboard
easy_iap: ^0.2.0 copied to clipboard

Simple and elegant in-app purchase SDK for Flutter. Unified API for iOS App Store and Google Play Store with functional patterns (fold, when) and multi-language support.

Easy IAP #

Simple and elegant in-app purchase SDK for Flutter.

pub package License: MIT

Features #

  • Simple API - Initialize once, purchase with one line
  • Functional patterns - fold, when, onSuccess, onFailure for clean error handling
  • Unified API - Same code for iOS App Store and Google Play Store
  • Auto-restore - Automatically restore purchases on app launch
  • Type-safe - Full Dart type safety with null safety
  • Testable - Built-in MockEasyIap for unit testing
  • Reactive - Stream-based ownership updates with IapBuilder widget

Installation #

dependencies:
  easy_iap: ^0.1.0

Quick Start #

1. Initialize #

import 'package:easy_iap/easy_iap.dart';

final iap = await EasyIap.init(
  products: [
    IapProduct.subscription('pro_monthly'),
    IapProduct.subscription('pro_yearly'),
    IapProduct.consumable('gems_100'),
    IapProduct.nonConsumable('remove_ads'),
  ],
);

2. Purchase #

final result = await iap.purchase('pro_monthly');

result.fold(
  onSuccess: (receipt) {
    print('Purchased: ${receipt.product.id}');
    unlockProFeatures();
  },
  onFailure: (failure) {
    print('Failed: ${failure.message}');
    showError(failure.displayMessage);
  },
);

3. Check Ownership #

// Check subscription
if (iap.hasActiveSubscription) {
  showProContent();
}

// Check specific product
if (iap.isOwned('remove_ads')) {
  hideAds();
}

// Check specific subscription
if (iap.hasSubscription('pro_monthly')) {
  showMonthlyBadge();
}

Result Handling #

result.fold(
  onSuccess: (receipt) => unlockFeature(),
  onFailure: (failure) => showError(failure.message),
);

Using when (with cancelled handling) #

result.when(
  success: (receipt) => unlockFeature(),
  cancelled: () => showSnackBar('Purchase cancelled'),
  failure: (failure) => showError(failure.message),
);

Using chaining #

result
  .onSuccess((receipt) => saveReceipt(receipt))
  .onFailure((failure) => logError(failure))
  .onCancelled(() => analytics.logCancelled());

Smart failure handling #

result.onFailure((failure) {
  if (failure.shouldIgnore) return;  // User cancelled

  if (failure.canRetry) {
    showRetryButton();
  } else if (failure.requiresUserAction) {
    showPaymentSettings();
  } else {
    showError(failure.displayMessage);
  }
});

Reactive UI #

IapBuilder #

IapBuilder(
  iap: iap,
  productId: 'pro_monthly',
  owned: () => ProScreen(),
  notOwned: () => UpgradeScreen(),
  loading: () => LoadingScreen(),
)

SubscriptionBuilder #

SubscriptionBuilder(
  iap: iap,
  subscribed: (subscriptions) => PremiumContent(subscriptions),
  notSubscribed: () => SubscribePrompt(),
)

PurchaseListener #

PurchaseListener(
  iap: iap,
  onPurchase: (receipt) {
    showSuccessAnimation();
    analytics.logPurchase(receipt);
  },
  child: YourContent(),
)

Product Types #

// One-time purchase, can buy multiple times (coins, gems)
IapProduct.consumable('gems_100')

// One-time purchase, permanent (remove ads, unlock level)
IapProduct.nonConsumable('remove_ads')

// Recurring payment (monthly, yearly subscription)
IapProduct.subscription('pro_monthly')

Server-Side Verification #

final iap = await EasyIap.init(
  products: [...],
  verifyPurchase: (receipt) async {
    // Send to your server for verification
    final response = await myApi.verifyPurchase(
      productId: receipt.product.id,
      token: receipt.purchaseToken,
      platform: Platform.isIOS ? 'ios' : 'android',
    );
    return response.isValid;
  },
);

Analytics Integration #

final iap = await EasyIap.init(
  products: [...],
  onPurchase: (receipt) async {
    await analytics.logPurchase(
      productId: receipt.product.id,
      price: receipt.product.price,
      isRestored: receipt.isRestored,
    );
  },
);

Testing #

MockEasyIap #

final mockIap = MockEasyIap(
  products: [
    IapProduct.subscription('pro_monthly'),
  ],
);

// Simulate successful purchase
mockIap.mockPurchaseSuccess('pro_monthly');

// Simulate failure
mockIap.mockPurchaseFailure('pro_monthly', 'payment_declined');

// Simulate cancellation
mockIap.mockPurchaseCancelled('pro_monthly');

// Set up owned products
mockIap.setOwned({'remove_ads'});
mockIap.addSubscription('pro_monthly');

Widget Testing #

testWidgets('shows pro content when subscribed', (tester) async {
  final mockIap = MockEasyIap(products: [...]);
  mockIap.addSubscription('pro_monthly');

  await tester.pumpWidget(
    MaterialApp(
      home: IapBuilder(
        iap: mockIap,
        productId: 'pro_monthly',
        owned: () => Text('Pro Content'),
        notOwned: () => Text('Upgrade'),
      ),
    ),
  );

  expect(find.text('Pro Content'), findsOneWidget);
});

Platform Setup #

iOS #

Add to ios/Runner/Info.plist:

<key>SKProductIdentifiers</key>
<array>
  <string>pro_monthly</string>
  <string>pro_yearly</string>
</array>

Android #

Add to android/app/build.gradle:

dependencies {
    implementation 'com.android.billingclient:billing:6.0.1'
}

Requirements #

Platform Minimum Version
Flutter 3.22.0
Dart 3.4.0
iOS 12.0
Android API 21

License #

MIT License - see LICENSE for details.

Contributing #

Contributions are welcome! Please read our contributing guidelines.

1
likes
150
points
127
downloads

Publisher

unverified uploader

Weekly Downloads

Simple and elegant in-app purchase SDK for Flutter. Unified API for iOS App Store and Google Play Store with functional patterns (fold, when) and multi-language support.

Repository (GitHub)
View/report issues
Contributing

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

collection, flutter, in_app_purchase, in_app_purchase_android, in_app_purchase_storekit, intl

More

Packages that depend on easy_iap