Search code examples
flutterin-app-purchase

flutter in_app_purchases not available on emulator - getting error android


I am trying to implement in_app_purchase: ^0.3.5+1 for 1st time. I have an active product setup on the Google Developer Console but I can't seem to get my emulator to hit the store. The connection's isAvailable method always returns false. Stepping through the code the connection instance seems to show the following error message in the private property _purchasedUpdatedStream. Not sure what this means. Seems relevant. Not sure what steps to take from here. Any help is much appreciated.

The getter '_purchaseUpdatedStream' isn't defined for the class 'GooglePlayConnection'.

  • 'GooglePlayConnection' is from 'package:in_app_purchase/src/in_app_purchase/google_play_connection.dart' ('../../flutterSDK/.pub-cache/hosted/pub.dartlang.org/in_app_purchase-0.3.5+1/lib/src/in_app_purchase/google_play_connection.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named '_purchaseUpdatedStream'. _purchaseUpdatedStream

Store class looks like this:

import 'dart:async';
import 'dart:io';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:quifil/models/status_ml.dart';

class StoreAPI {
  InAppPurchaseConnection _iap;
  bool available = true;
  StreamSubscription<List<PurchaseDetails>> _subscription;
  final String myProductID = 'quifil_ad_free';
  bool _isPurchased = false;
  List _purchases = [];
  List _products = [];

  StoreAPI() {
    InAppPurchaseConnection.enablePendingPurchases();
    _iap = InAppPurchaseConnection.instance;
  }

  bool get isPurchased {
    return _isPurchased;
  }

  set isPurchased(bool value) {
    _isPurchased = value;
  }

  List get purchases {
    return _purchases;
  }

  set purchases(List value) {
    _purchases = value;
  }

  List get products {
    return _products;
  }

  set products(List value) {
    _products = value;
  }

  Future<Status> fetchStoreInfo() async {
    Status status = Status(true);
    bool available = await _iap.isAvailable();
    if (available) {
      await _getProducts();
      await _getPastPurchases();
      verifyPurchase();
      _subscription = _iap.purchaseUpdatedStream.listen((purchases) {
        purchases.addAll(purchases);
        verifyPurchase();
      });
    } else {
      status.success = false;
      status.error = "Store is unavailable";
    }
    return status;
  }

  Future<void> _getProducts() async {
    Set<String> ids = Set.from([myProductID]);
    ProductDetailsResponse response = await _iap.queryProductDetails(ids);
    products = response.productDetails;
  }

  Future<void> _getPastPurchases() async {
    QueryPurchaseDetailsResponse response = await _iap.queryPastPurchases();
    for (PurchaseDetails purchase in response.pastPurchases) {
      if (Platform.isIOS) {
        _iap.consumePurchase(purchase);
      }
    }
    purchases = response.pastPurchases;
  }

  void verifyPurchase() {
    PurchaseDetails purchase = hasPurchased(myProductID);
    if (purchase != null && purchase.status == PurchaseStatus.purchased) {
      if (purchase.pendingCompletePurchase) {
        _iap.completePurchase(purchase);
        isPurchased = true;
      }
    }
  }

  PurchaseDetails hasPurchased(String productID) {
    return purchases.firstWhere((purchase) => purchase.productID == productID,
        orElse: () => null);
  }
}

Solution

  • Turns out I had 2 items I changed to fix this.

    My laptop was using wifi but wifi was not the 1st choice when it came to network access. So I disabled my other other LAN adapters. There is also a way to set the priority of your adaptors so that the wifi is top priority. It seems the emulator likes to pick the top priority.

    My laptop wifi adapter DNS was using an address I did not recognize. So I changed it to use Google's DNS as 8.8.8.8 and the alternate as 8.8.4.4.