GraSim
GraSim

Reputation: 4210

Flutter in_app_purchase purchaseStream.listen not firing any events 3.0.6

I'm trying to implement purchases in my app with the official in_app_purchase plugin but the purchaseStream.listen method is not working or firing any events. The only way to get it to work is to call _inAppPurchase.restorePurchases() which is not what I want as the products are now returned with a restored (not purchased) status.

Can anyone advise on how to get this event firing or point out any mistakes in my code? My code is almost exactly the same as the codelab and I have tested with the plugin version used in the codelab ^3.0.4 as well as the latest version ^3.0.6

class PurchasesModel with ChangeNotifier {
  final InAppPurchase _inAppPurchase = InAppPurchase.instance;
  late StreamSubscription<List<PurchaseDetails>> _subscription;

  List _purchases = [];
  List<ProductDetails> _products = [];

  List get purchases => _purchases;
  set purchases(List value) {
    _purchases = value;
    notifyListeners();
  }

  List<ProductDetails> get products => _products;
  set products(List<ProductDetails> value) {
    _products = value;
    notifyListeners();
  }

  //Constructor
  PurchasesModel() {
    final purchaseUpdated = _inAppPurchase.purchaseStream;
    _subscription = purchaseUpdated.listen(
      _onPurchaseUpdate,
      onDone: _updateStreamOnDone,
      onError: _updateStreamOnError,
    );
    loadPurchases();
  }

  Future<void> _onPurchaseUpdate(List<PurchaseDetails> purchaseDetailsList) async {
    for (var purchaseDetails in purchaseDetailsList) {
      await _handlePurchase(purchaseDetails);
    }
    notifyListeners();
  }

  Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async {
    ....
  }


  void _updateStreamOnDone() {
    _subscription.cancel();
  }

  void _updateStreamOnError(dynamic error) {
    // ignore: avoid_print
    print(error);
  }

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

And the Widget build method in main.dart

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<PurchasesModel>(
          create: (_) => PurchasesModel(),
          lazy: false,
        ),
      ],
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData.dark().copyWith(
          primaryColor: primaryColor,
          scaffoldBackgroundColor: backgroundColor,
        ),
        home: App(),
      ),
    );
  }

Upvotes: 1

Views: 1821

Answers (1)

Kaushik Chandru
Kaushik Chandru

Reputation: 17732

This event is triggered only when there is a response for purchase or restore. So first you get the list of products available for sale. That's the

// Set literals require Dart 2.2. Alternatively, use
// `Set<String> _kIds = <String>['product1', 'product2'].toSet()`.
const Set<String> _kIds = <String>{'product1', 'product2'};
final ProductDetailsResponse response =
    await InAppPurchase.instance.queryProductDetails(_kIds);
if (response.notFoundIDs.isNotEmpty) {
  // Handle the error.
}
List<ProductDetails> products = response.productDetails;

Here you will get the list of products for sale .

Then when there is a purchase event we use

final ProductDetails productDetails = ... // Saved earlier from queryProductDetails().
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
if (_isConsumable(productDetails)) {
  InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
} else {
  InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam);
}
// From here the purchase flow will be handled by the underlying store.
// Updates will be delivered to the `InAppPurchase.instance.purchaseStream`.

Here we pass one product detail to buy consumable or buy non consumable and this is listened in the method you mentioned

Edit To restore you just call this methos and it will be listened in the listener

await InAppPurchase.instance.restorePurchases();

Upvotes: 1

Related Questions