In-App Purchases with Flutter: A Comprehensive Guide

Published on by Flutter News Hub

In-App Purchases with Flutter: A Comprehensive Guide

In-app purchases (IAPs) allow mobile app users to purchase digital goods or services within an app. The Flutter In-App Purchase plugin provides a unified, cross-platform interface for implementing IAPs in Flutter apps. This guide will walk you through the process of setting up and using the plugin to integrate IAPs into your app.

Prerequisites

  • Flutter SDK 2.2+
  • iOS 12.0+ (for App Store)
  • Android SDK 16+ (for Google Play)
  • Completed IAP setup in App Store and Google Play

Getting Started

  1. Install the plugin:

    dependencies:
      in_app_purchase: ^3.0.0
    
  2. Import the plugin:

    import 'package:in_app_purchase/in_app_purchase.dart';
    
  3. Connect to the store:

    InAppPurchase.instance.isAvailable(); // Check if the store is available
    
  4. Load product details:

    final Set ids = {'product1', 'product2'};
    final ProductDetailsResponse response = await InAppPurchase.instance.queryProductDetails(ids);
    final List products = response.productDetails;
    
  5. Start a purchase:

    final ProductDetails productDetails = ...;
    if (productDetails.isConsumable) {
        InAppPurchase.instance.buyConsumable(purchaseParam: PurchaseParam(productDetails: productDetails));
    } else {
        InAppPurchase.instance.buyNonConsumable(purchaseParam: PurchaseParam(productDetails: productDetails));
    }
    

Handling Purchase Updates

Listen for purchase updates on the InAppPurchase.instance.purchaseStream:

_subscription = InAppPurchase.instance.purchaseStream.listen((purchaseDetailsList) {
  _listenToPurchaseUpdated(purchaseDetailsList);
}, onDone: () {
  _subscription.cancel();
}, onError: (error) {
  // Handle error
});

In the _listenToPurchaseUpdated method:

void _listenToPurchaseUpdated(List purchaseDetailsList) {
  purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
    if (purchaseDetails.status == PurchaseStatus.purchased || purchaseDetails.status == PurchaseStatus.restored) {
      bool valid = await _verifyPurchase(purchaseDetails);
      if (valid) {
        _deliverProduct(purchaseDetails);
      } else {
        _handleInvalidPurchase(purchaseDetails);
      }
    }
    if (purchaseDetails.pendingCompletePurchase) {
      await InAppPurchase.instance.completePurchase(purchaseDetails);
    }
  });
}

Restoring Previous Purchases

InAppPurchase.instance.restorePurchases();

Platform-Specific Considerations

The plugin provides both cross-platform and platform-specific APIs:

  • Generic Flutter API (in_app_purchase): Use for most IAP use cases.
  • Platform-specific Dart APIs (store_kit_wrappers, billing_client_wrappers): Allow for finer control and access to platform-specific features (but require different purchase handling logic for different platforms).

Code Examples

Load and Purchase a Product:

// Get a specific product
final ProductDetails product = products.firstWhere((product) => product.id == 'my_product');

// Start the purchase
if (product.isConsumable) {
  InAppPurchase.instance.buyConsumable(productDetails: product);
} else {
  InAppPurchase.instance.buyNonConsumable(productDetails: product);
}

// Complete the purchase
_listenToPurchaseUpdated((purchaseDetailsList) {
  purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) {
    if (purchaseDetails.id == productId && purchaseDetails.status == PurchaseStatus.purchased) {
      InAppPurchase.instance.completePurchase(purchaseDetails);
    }
  });
});

Handle Purchase Verification:

Future _verifyPurchase(PurchaseDetails purchaseDetails) async {
  // Validate receipt on server-side
  final bool isValid = await server.validateReceipt(purchaseDetails.verificationData);
  return isValid;
}

Access Platform-Specific Properties:

Android (Google Play):

if (purchaseDetails is GooglePlayPurchaseDetails) {
  final BillingClientPurchase billingClientPurchase = purchaseDetails.billingClientPurchase;
  // Access platform-specific properties, such as `originalJson`
}

iOS (App Store):

if (purchaseDetails is AppStorePurchaseDetails) {
  final SKPaymentTransactionWrapper transaction = purchaseDetails.skPaymentTransaction;
  // Access platform-specific properties, such as `transactionState`
}

Redeem Offer Codes (iOS 14+):

final InAppPurchaseStoreKitPlatformAddition platformAddition = InAppPurchase.getPlatformAddition();
platformAddition.presentCodeRedemptionSheet();

Conclusion

The Flutter In-App Purchase plugin simplifies the integration of IAPs into your Flutter apps. By following the steps and examples outlined in this guide, you can provide users with a seamless purchasing experience on both iOS and Android platforms.

Flutter News Hub