Play Billing 1.0:如何知晓订阅已取消?未实现queryPurchases是否有影响?
Hey there! Let's dig into your problem and fix that subscription cancellation detection gap.
Short Answer: Yes, Missing queryPurchases Implementation Is Likely the Root Cause
The Play Billing Library doesn’t automatically push subscription status changes (like cancellations, expirations, or refunds) to your app. You need to actively fetch the latest purchase state, and the queryPurchases (or its modern async counterpart) is the core method for doing this. Without it, your app has no way to check if a user canceled their subscription after the initial purchase.
Step-by-Step Fixes
1. Implement the Async Purchase Query (Recommended Over Deprecated Sync Method)
The old queryPurchases method is deprecated, so use queryPurchasesAsync for subscriptions in your BillingManager.java. This will fetch all active and inactive subscriptions tied to the user's account:
private static final String TAG = "BillingManager"; public void fetchCurrentSubscriptions() { if (!billingClient.isReady()) { Log.w(TAG, "BillingClient isn't ready yet—wait for initialization first!"); return; } QueryPurchasesParams params = QueryPurchasesParams.newBuilder() .setProductType(BillingClient.SkuType.SUBS) .build(); billingClient.queryPurchasesAsync(params, new PurchasesResponseListener() { @Override public void onQueryPurchasesResponse(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { updateSubscriptionStatus(purchases); } else { Log.e(TAG, "Failed to fetch subscriptions: " + billingResult.getDebugMessage()); } } }); } // Helper method to process subscription states private void updateSubscriptionStatus(List<Purchase> purchases) { for (Purchase purchase : purchases) { // Check if auto-renew is disabled (user canceled subscription) boolean isSubscriptionCanceled = !purchase.isAutoRenewing(); // Check purchase state (PURCHASED = active, PENDING = waiting for payment, etc.) int purchaseState = purchase.getPurchaseState(); if (isSubscriptionCanceled) { // Handle cancellation logic here (e.g., update UI, restrict premium features) Log.i(TAG, "User canceled subscription for SKU: " + purchase.getSkus().get(0)); } else if (purchaseState == Purchase.PurchaseState.PURCHASED) { // Subscription is active Log.i(TAG, "Active subscription for SKU: " + purchase.getSkus().get(0)); } } }
2. Add Real-Time Purchase Update Listener
Catch immediate subscription changes (like when a user cancels via Google Play while your app is open) by setting a PurchasesUpdatedListener when initializing the BillingClient:
billingClient = BillingClient.newBuilder(context) .setListener(new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) { updateSubscriptionStatus(purchases); } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { // Note: This only means the user canceled the current purchase flow, not their existing subscription Log.i(TAG, "User exited the purchase flow"); } else { Log.e(TAG, "Purchase update error: " + billingResult.getDebugMessage()); } } }) .enablePendingPurchases() // Required for handling pending payments .build();
3. Schedule Regular Subscription Checks
Since some status changes (like subscription expiration) won't trigger a real-time callback, schedule periodic calls to fetchCurrentSubscriptions():
- Call it when your app starts up
- Set a daily background task (using WorkManager, for example) to refresh the status
4. Validate Subscriptions on Your Backend (Optional but Critical for Security)
To prevent client-side tampering, send the purchase.getPurchaseToken() to your backend server. Use the Google Play Developer API's subscription verification endpoint to confirm the true subscription status (including cancellation date, expiration time, and auto-renew status). This is the most reliable way to confirm subscription state.
Final Notes
Once you implement the queryPurchasesAsync flow and combine it with real-time listening and periodic checks, your app will accurately detect when a user cancels their subscription. Don't forget to test edge cases, like users canceling and then resubscribing, to ensure your logic handles all scenarios correctly.
内容的提问来源于stack exchange,提问作者CJara

