In App Purchase 似乎被多次调用

In App Purchase seems to be called multiple times

我根据 Google 的教程使用 Play Billing Library 1.0 实现了应用内购买。 我只有 1 件商品可供购买,解锁后,我会显示一条长度为 Toast.LENGTH_SHORT 的 Toast 消息。但是,Toast 在那里停留了大约 10 秒钟,所以我假设它被调用了多次。当我通过 queryPurchases 解锁它时,它不会发生(如果有人早些时候购买它并同时重新安装应用程序)。

有人知道为什么 Toast 保持这么久/为什么它被多次调用吗?

在我的 BillingManager 中 class:

@Override
public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
    if (responseCode == BillingClient.BillingResponse.OK) {
        for (Purchase purchase : purchases) {
            handlePurchases(purchase);
        }
        mBillingUpdatesListener.onPurchasesUpdated(mPurchases);
    } else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {

    } else {

    }
}

public void handlePurchases(Purchase purchase) {
    //here could be validation on own server

    mPurchases.add(purchase);
}

主要 Activity 实现 BillingUpdatesListener:

@Override
public void onPurchasesUpdated(List<Purchase> purchases) {
    for (Purchase purchase : purchases) {
        switch (purchase.getSku()) {
            case "premium":
                unlockPremium();
                break;
        }
    }
}

public void unlockPremium() {
    mPremiumUnlocked = true;
    savePremiumUnlocked();
    Toast.makeText(this, getResources().getString(R.string.premium_congrats), Toast.LENGTH_SHORT).show();
    mAdView.setVisibility(GONE);
}

如果我没理解错的话,你是说当你第一次购买应用内商品时,你会得到多个 Toasts?

在当前版本 (1.0) 的 Billing 库中,发生这种情况是因为系统正在进行多个广播。

例如,如果您在图书馆 BillingClientImpl.java 的第 120 行查看或断点 onPurchaseFinishedReceiver,则在购买后至少调用两次。两次都附加了应用内购买数据,但我注意到每次广播的意图 Action 都不同。

在第一次广播中,Action 是 com.android.vending.billing.PURCHASES_UPDATED,但在第二次广播中是 proxy_activity_response_intent_action。该库不会过滤掉 Action 值,因此所有这些广播都会导致您的 purchasesUpdatedListener 被调用。

我没有进一步调查,但我认为我们可以从中得出的结论是发生了某种变化,我们认为有必要广播该变化。

为避免多次吐司,除非您的高级功能已解锁,否则请不要显示吐司。即如果它已经解锁,只需忽略更改通知。

顺便说一下,完全可以在 Android Studio 中调试购买流程。只需使用您的发布密钥签署您的调试 apk,并确保 apk 版本不高于 Play 商店中的版本。

buildTypes {

    debug {
        minifyEnabled false
        debuggable true
        signingConfig signingConfigs.release
    }


    release {
        minifyEnabled false
        signingConfig signingConfigs.release
    }
}

@Kuffs 的出色回答和深入探讨!

Google 将很快修复多个调用:https://issuetracker.google.com/issues/66054158

但是,即使多次触发 onPurchasesUpdate,您与计费流程的集成也应该有效,因为它无论如何都可能发生。例如,如果有人使用相同的@gmail 帐户在另一台设备上同时购买。一些国家(例如西班牙)的人们确实经常与许多朋友和家人共享他们的@gmail 帐户。

请检查 TrivialDrive_v2 实现以了解如何优雅地处理此类情况。

我不知道这是否适用于您的具体情况,但我们遇到了同样的事情,这是 Google 端的错误。

有关详细信息,请参阅 https://issuetracker.google.com/issues/66054158

编辑:我刚刚看到@goRGon 发布了同样的内容:)

西班牙多人的例子与上述情况不同。在西班牙的场景中,用户实际上购买了两份 IAP,因此它们是两张单独的收据,用户应该得到两份他们购买的东西的奖励。在 bug 场景中,一张收据被呈现给用户两次,因此实际上可以捕获重复的收据。但无论哪种方式,后端验证系统都需要在可能导致同一收据连续发送两次的代码中容纳 hackers/bugs。


希望对你有所帮助

        _purchaseUpdatedSubscription =
        FlutterInappPurchase.purchaseUpdated.listen((productItem) {
      print('purchase-updated: ${productItem}');
      getDetails(productItem);
    });

        String orderId = '';
      getDetails(PurchasedItem purchasedItem) {
        if (purchasedItem != null) {
          if (orderId != purchasedItem.orderId) {
            orderId = purchasedItem.orderId;
            print('productItem.transactionReceipt : ${purchasedItem.transactionReceipt}');
            var decodedData = jsonDecode(purchasedItem.transactionReceipt);
            print('purchaseState : ${decodedData['purchaseTime']}');
    
            if (decodedData['purchaseState'] == 0) {
    
              if(purchasedItem.productId == selected_package) {
                print("Purchased successfully");
                onPurchased(purchasedItem);
              }
            } else {
              ShowMsg('Transaction Failed !, Something went wrong.');
            }
          }
        }
      }

如果您的订阅 activity 在同一申请流程中多次关闭并重新打开,则 onPurchasesUpdated may be called multiple times if the PurchasesUpdatedListener somehow stays attached to the previous instances of billingClient and if the previous connections are still alive. I noticed that the number of times I closed and reopened the subscription activity, onPurchasesUpdated was called for the same amount after a successful launchBillingFlow

为了解决这个问题,我需要在 activity 被破坏时 end the connection,就像这样 -

@Override
protected void onDestroy() {
    super.onDestroy();
    if (billingClient!= null) {
        billingClient.endConnection();
    }
}