flutter_in_app_purchase_helper 0.1.0 copy "flutter_in_app_purchase_helper: ^0.1.0" to clipboard
flutter_in_app_purchase_helper: ^0.1.0 copied to clipboard

A Flutter in-app purchase helper that handles product lookup, purchase flows, restores and transaction completion.

Flutter In-App Purchase Helper #

A thin, tested wrapper around in_app_purchase that handles the bookkeeping most integrations get wrong: completing transactions, telling pending and canceled purchases apart from real failures, and surfacing store misconfiguration instead of silently returning an empty product list.

Install #

dependencies:
  flutter_in_app_purchase_helper: ^0.1.0

You still need to configure your products in Play Console and App Store Connect, and follow the platform setup in the in_app_purchase README.

Usage #

Initialize #

Create the helper, then initialize it with your product IDs and the callbacks you care about. Only the first four are required.

import 'package:flutter_in_app_purchase_helper/flutter_in_app_purchase_helper.dart';

final FlutterInAppPurchaseHelper _helper = FlutterInAppPurchaseHelper();

@override
void initState() {
  super.initState();
  _helper.initialize(
    productIds: {'monthly_plan', 'yearly_plan'},
    onProductsFetched: (products) {
      setState(() => _products = products);
    },
    onPurchaseSuccess: (purchase) {
      // Fires for both new purchases and restores.
      _unlockContent(purchase);
    },
    onPurchaseError: (error) {
      _showSnackBar(error);
    },
    // Optional:
    onPurchasePending: (purchase) => _showSpinner(),
    onPurchaseCanceled: (purchase) => _hideSpinner(),
  );
}

Calling initialize more than once is a no-op until you dispose, so a rebuild cannot register duplicate listeners.

Show the products #

onProductsFetched gives you ProductDetails straight from the store, so prices and currencies are already localized. Use product.price rather than formatting rawPrice yourself.

ListView.builder(
  itemCount: _products.length,
  itemBuilder: (context, index) {
    final product = _products[index];
    return ListTile(
      title: Text(product.title),
      subtitle: Text(product.description),
      trailing: Text(product.price),
      onTap: () => setState(() => _selected = product),
    );
  },
)

Buy #

final sent = await _helper.buyProduct(product, (error) => _showSnackBar(error));

if (!sent) {
  // The request never reached the store; stop any spinner you started.
}

buyProduct returns whether the request was sent. The outcome arrives on the callbacks you gave to initialize.

For consumables, pass consumable: true:

await _helper.buyProduct(coinPack, _showSnackBar, consumable: true);

Restore #

The App Store requires a restore entry point for any app selling non-consumables or subscriptions. Restored purchases arrive on onPurchaseSuccess.

TextButton(
  onPressed: () => _helper.restorePurchases(onError: _showSnackBar),
  child: const Text('Restore purchases'),
)

Dispose #

@override
void dispose() {
  _helper.dispose();
  super.dispose();
}

Verifying purchases #

onPurchaseSuccess fires on the client's word alone. For anything revenue-bearing, send purchase.verificationData.serverVerificationData to your backend and validate it with Apple or Google before unlocking content.

What the helper handles for you #

Concern Behaviour
Transaction completion completePurchase is called on every finished transaction. Skipping this makes iOS re-deliver the transaction on every launch, and makes Google Play auto-refund the purchase after 3 days.
Pending purchases Routed to onPurchasePending, never to onPurchaseError. Never completed, which would throw.
Cancellations Routed to onPurchaseCanceled, never to onPurchaseError.
Restores Routed to onPurchaseSuccess.
Unknown product IDs Reported through onPurchaseError with the offending IDs, instead of an empty list.
Slow stores queryProductDetails is bounded by timeout (30s default).
Double initialization Ignored, so you cannot leak a second stream listener.
Disposal Safe even if initialize was never called or the store was unavailable.

API #

Member Description
initialize({productIds, onProductsFetched, onPurchaseSuccess, onPurchaseError, onPurchasePending, onPurchaseCanceled, timeout}) Checks availability, fetches products, starts listening.
buyProduct(product, onError, {consumable, autoConsume}) Starts a purchase. Returns whether the request was sent.
restorePurchases({applicationUserName, onError}) Restores non-consumables and subscriptions.
dispose() Cancels the purchase stream subscription.
isAvailable Whether the store is available on this device.
isInitialized Whether the helper is currently initialized.
products Products from the most recent fetch.
purchases Most recent purchase per product ID.

Example #

A complete plan-picker screen lives in example/lib/main.dart.

License #

MIT — see LICENSE.

5
likes
150
points
37
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter in-app purchase helper that handles product lookup, purchase flows, restores and transaction completion.

Repository (GitHub)
View/report issues

Topics

#in-app-purchase #iap #billing #subscriptions #payments

License

unknown (license)

Dependencies

flutter, in_app_purchase, in_app_purchase_platform_interface

More

Packages that depend on flutter_in_app_purchase_helper