title: How to use in_app_purchase using BLoC?
body: <p>I'm trying to refactor my code a little bit, and I want to refactor payment logic using BLoC.
  The problem is that I'm still getting an error that says:</p>
  <blockquote>
  <p>emit was called after an event handler completed normally.</p>
  </blockquote>
  <p><a href="https://i.stack.imgur.com/ON5Zn.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ON5Zn.png" alt="enter image description here" /></a></p>
  <p>I only need information from state if the transaction is Pending, Complete or there is an error, so there is only true or false to show the CircularIndicator.</p>
  <p>There is my try to implement Payment using BLoC.</p>
  <blockquote>
  <p>_onStarted - starts subscription and is called once on initState</p>
  </blockquote>
  <blockquote>
  <p>_buyProduct - is called when user hits the button</p>
  </blockquote>
  <pre><code>class PaymentBloc extends Bloc&lt;PaymentEvent, PaymentState&gt; {
  
    static const bool _started = false;
    final InAppPurchase _inAppPurchase = InAppPurchase.instance;
    Set&lt;String&gt; _kProductIds = {&quot;mini_burger_4_99&quot;};
    List&lt;ProductDetails&gt; _products = [];
  
    PaymentBloc() : super(PaymentInitial(_started)) {
      on&lt;PaymentStarted&gt;(_onStarted);
      on&lt;PaymentCompletion&gt;(_buyProduct);
    }
  
    StreamSubscription&lt;List&lt;PurchaseDetails&gt;&gt;? _subscription;
  
    void _onStarted(PaymentStarted event, Emitter&lt;PaymentState&gt; emit) {
      final Stream&lt;List&lt;PurchaseDetails&gt;&gt; purchaseUpdated =
          _inAppPurchase.purchaseStream;
  
      _subscription = purchaseUpdated.listen((purchaseDetailsList) {
        purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
          if (purchaseDetails.status == PurchaseStatus.pending) {
            emit(PaymentPending());
          } else {
            if (purchaseDetails.status == PurchaseStatus.error) {
              emit(PaymentError());
            } else if (purchaseDetails.pendingCompletePurchase) {
              await _inAppPurchase.completePurchase(purchaseDetails);
              emit(PaymentComplete());
            }
          }
        });
      }, onDone: () {
        _subscription?.cancel();
      }, onError: (error) {
        // handle error.
      });
  
      initStoreInfo();
    }
  
    Future&lt;void&gt; _buyProduct(
        PaymentCompletion event, Emitter&lt;PaymentState&gt; emit) async {
      var paymentWrapper = SKPaymentQueueWrapper();
      var transactions = await paymentWrapper.transactions();
      transactions.forEach((transaction) async {
        await paymentWrapper.finishTransaction(transaction);
      });
      final PurchaseParam purchaseParam = PurchaseParam(
          productDetails:
              _products.firstWhere((product) =&gt; product.id == event.id));
      await _inAppPurchase.buyConsumable(purchaseParam: purchaseParam);
    }
  
    @override
    Future&lt;void&gt; close() {
      _subscription?.cancel();
      return super.close();
    }
  
    Future&lt;void&gt; initStoreInfo() async {
      final bool isAvailable = await _inAppPurchase.isAvailable();
  
      if (!isAvailable) {
        _products = [];
        return;
      }
  
      if (Platform.isIOS) {
        var iosPlatformAddition = _inAppPurchase
            .getPlatformAddition&lt;InAppPurchaseIosPlatformAddition&gt;();
        await iosPlatformAddition.setDelegate(ExamplePaymentQueueDelegate());
      }
  
      ProductDetailsResponse productDetailResponse =
          await _inAppPurchase.queryProductDetails(_kProductIds);
  
      if (productDetailResponse.error != null) {
        _products = productDetailResponse.productDetails;
        return;
      }
  
      if (productDetailResponse.productDetails.isEmpty) {
        _products = productDetailResponse.productDetails;
        return;
      }
  
      _products = productDetailResponse.productDetails;
    }
  }
  </code></pre>
  <p>Thanks for any kind of help.</p>
  <p>Matt</p>