Search code examples
androidfluttergoogle-playflutter-in-app-purchase

Restore purchase not working in Flutter/Google Play


I have implemented in app purchases (IAP) as per in_app_purchase package example

I am able to buy a product from the store (I only have one set up). But when it comes to testing "user has a new phone" scenario, the restore purchases does not seem to work. No error either.

I've implemented this in a provider pattern. Store connection is initialized like this:

_isStoreAvailable = await _inAppPurchase.isAvailable();

Purchasing is implemented this way:

 Future<void> initializePurchase() async {
      ProductDetailsResponse response =
          await _inAppPurchase.queryProductDetails(_productIds);
      if (response.notFoundIDs.isNotEmpty) {
        // Handle the error.
        print("not found product in store!)");
      } else {
        PurchaseParam purchaseParam = PurchaseParam(
          productDetails: response.productDetails.first,
        );
        _inAppPurchase.buyNonConsumable(purchaseParam: purchaseParam);
      }
  }

I listen for changes using this code:

  final Stream<List<PurchaseDetails>> purchaseUpdated =
        _inAppPurchase.purchaseStream;
    _subscription =
        purchaseUpdated.listen((List<PurchaseDetails> purchaseDetailsList) {
      _listenToPurchaseUpdated(purchaseDetailsList);
    }, onDone: () {
      _subscription.cancel();
    }, onError: (error) {
      print("listen error: $error");
    });

...and this

  Future<void> _listenToPurchaseUpdated(
      List<PurchaseDetails> purchaseDetailsList) async {
    for (final PurchaseDetails purchaseDetails in purchaseDetailsList) {
      if (purchaseDetails.status != PurchaseStatus.pending) {
        if (purchaseDetails.status == PurchaseStatus.error) {
          //handle error
        } else if (purchaseDetails.status == PurchaseStatus.purchased ||
            purchaseDetails.status == PurchaseStatus.restored) {

          setLicense(StoreLicenseStatus.paid);
          notifyListeners();

          if (purchaseDetails.pendingCompletePurchase) {
            await _inAppPurchase.completePurchase(purchaseDetails);
          }
        }
      }
    }
  }

User can request purchases to be restored using this code:

 Future<void> restorePurchases() async {
    await _inAppPurchase.restorePurchases();
  }

Everything except restore works. I can buy a product, clear data, and when I start the app again, if I try to buy, I get a message from the store "you already own this item". So the store recognizes that the product was already purchased, great! But when I click "restore" nothing happens.

Am I missing something here?

This is on an emulator (Pixel 4 API 32), also on a real device.


Solution

  • This is caused by a bug in in_app_purchase_android package.

    The new billing api uses an asynchronous listener in queryPurchasesAsync. There was a change that has the listener be invoked on the background thread instead of the main UI thread, which is causing the querypurchases to never complete.

    In the meantime add this to your pubspec.yaml as a workaround:

    dependency_overrides:
    in_app_purchase_android: 0.2.2+8
    

    For more details see this GitHub issue