Flutter's in_app_purchase plugin has been updated to version 0.3.0, migrating the Google Play Library to 2.0.3.
According to the Google Play Library v2, all purchases have to be acknowledged within 3 days (or 5 minutes in the case of test orders) or they will be canceled automatically.
In the latest commit of in_app_purchase, a method called acknowledgePurchase is added to the BillingClient class. However, the current documented way of making an in-app purchase is via InAppPurchaseConnection.instance which does not provide any method to acknowledge a purchase.

A generic implementation of in_app_purchase looks like this:

// Listening for new purchases
final Stream purchaseUpdates = InAppPurchaseConnection.instance.purchaseUpdatedStream;
StreamSubscription<List<PurchaseDetails>> _subscription = purchaseUpdates.listen((purchases) {
    _handlePurchaseUpdates(purchases);
});

// Product Details
ProductDetailsResponse _productDetailsResponse = await InAppPurchaseConnection.instance.queryProductDetails(this.productIDs.toSet());

// Past Purchases
QueryPurchaseDetailsResponse _purchaseDetailsResponse = await InAppPurchaseConnection.instance.queryPastPurchases();

// Making an nonConsumable purchase
PurchaseParam param = PurchaseParam(
    productDetails: productDetails,
    applicationUserName: null,
    sandboxTesting: sandboxTesting
);
InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: param);

Once the purchase is made and verified, the product is delivered. But how can we acknowledge the new purchases while listening for new purchases and acknowledge the old ones (if they are not acknowledged) while getting the list of past purchases?


Solution 1: loomp

I was looking for the solution as well, looks like it is described within release notes. https://pub.dev/packages/in_app_purchase#-changelog-tab-

For example, while fetching past purchases:


// at top class level (i.e. App wrapper)
InAppPurchaseConnection.enablePendingPurchases();

// inside class handling the purchases
final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance;

// example use

final QueryPurchaseDetailsResponse purchaseResponse = await _connection.queryPastPurchases();

if (purchaseResponse.error != null) {
  // (handle error)
} else {
  // (purge local store)

  await Future.forEach<PurchaseDetails>(
      purchaseResponse.pastPurchases, (purchaseDetails) async {
          if (await _verifyPurchase(purchaseDetails)) {
            await //(insert purchase to local store);

            final pending = Platform.isIOS
                ? purchaseDetails.pendingCompletePurchase
                : !purchaseDetails.billingClientPurchase.isAcknowledged;

            if (pending) {
              await _connection.completePurchase(purchaseDetails);
            }
          }
        }
    );
}

Formerly, step _connection.competePurchase was intended for iOS only, now it is required for Android as well.

purchaseDetails.pendingCompletePurchase is true if purchase requires to be completed (iOS and Android).

purchaseDetails.billingClientPurchase.isAcknowledged additional check for Android added to make sure the completePurchase is executed when needed.

0.3.0

Other Updates to the "billing_client_wrappers": Updates to the PurchaseWrapper: Add developerPayload, purchaseState and isAcknowledged fields.

Updates to the "InAppPurchaseConnection": [Breaking Change]: InAppPurchaseConnection.completePurchase now returns a Future instead of Future. A new optional parameter {String developerPayload} has also been added to the API. On Android, this API does not throw an exception anymore, it instead acknowledge the purchase. If a purchase is not completed within 3 days on Android, the user will be refunded.

[Breaking Change]: InAppPurchaseConnection.consumePurchase now returns a Future instead of Future. A new optional parameter {String developerPayload} has also been added to the API. A new boolean field pendingCompletePurchase has been added to the PurchaseDetails class. Which can be used as an indicator of whether to call InAppPurchaseConnection.completePurchase on the purchase.

[Breaking Change]: Added enablePendingPurchases in InAppPurchaseConnection. The application has to call this method when initializing the InAppPurchaseConnection on Android. See enablePendingPurchases for more information.