
本教程详细阐述了如何在android应用中,使用google play billing library的`querypurchasesasync()`方法来检查用户的现有订阅状态,尤其是在应用启动时。文章将解释该方法与实时购买事件监听器(`purchasesupdatedlistener`)的区别,并提供完整的代码示例和最佳实践,确保用户订阅状态的准确性与安全性。
在Android应用中,管理用户订阅状态是实现内购功能的核心环节。当用户购买了订阅服务后,应用需要能够随时查询并验证该订阅的有效性,而不仅仅是在购买流程完成的当下。例如,当用户重新打开应用时,应用需要知道用户是否仍然拥有有效的订阅。
Google Play Billing Library 提供了两种主要机制来处理购买信息:
- PurchasesUpdatedListener: 用于监听实时发生的购买事件,例如用户完成新的购买流程或取消支付。
- queryPurchasesAsync(): 用于查询用户当前已拥有的所有有效购买(包括订阅)。这是在应用启动或需要验证用户现有订阅状态时应使用的主要方法。
核心方法:查询现有订阅 queryPurchasesAsync()
queryPurchasesAsync() 方法是专门设计用来检索与用户Google账户关联的所有有效购买(包括订阅和非消耗性商品)的。它是一个异步操作,通过回调 PurchasesResponseListener 返回查询结果。
实现步骤与代码示例
在使用 queryPurchasesAsync() 之前,请确保您的 BillingClient 实例已正确初始化并连接到 Google Play 服务。
立即学习“Java免费学习笔记(深入)”;
import android.util.Log;
import com.android.billingclient.api.AcknowledgePurchaseParams;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.QueryPurchasesParams;
import java.util.List;
public class SubscriptionManager {
private BillingClient billingClient;
private static final String TAG = "SubscriptionManager";
// 构造函数或初始化方法中传入 BillingClient 实例
public SubscriptionManager(BillingClient client) {
this.billingClient = client;
}
/**
* 检查用户当前的订阅状态。
* 此方法应在 BillingClient 连接成功后调用。
*/
public void checkSubscriptionStatus() {
if (billingClient != null && billingClient.isReady()) {
// 查询订阅类型商品
billingClient.queryPurchasesAsync(
QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build(),
(billingResult, purchases) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
boolean hasActiveSubscription = false;
if (purchases != null && !purchases.isEmpty()) {
for (Purchase purchase : purchases) {
// 验证购买状态和商品ID
// 请替换 "your_subscription_product_id" 为您实际的订阅商品ID
if (purchase.getProducts().contains("your_subscription_product_id") &&
purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
// 如果购买未被确认,则需要确认
if (!purchase.isAcknowledged()) {
acknowledgePurchase(purchase);
}
// 购买已确认且状态为已购买,则视为有效订阅
if (purchase.isAcknowledged()) {
hasActiveSubscription = true;
Log.d(TAG, "用户拥有有效订阅: OrderId = " + purchase.getOrderId());
// TODO: 根据您的应用逻辑更新UI或应用状态
// 例如: Constant.subscription = true;
break; // 找到一个有效订阅即可
}
}
}
}
if (!hasActiveSubscription) {
Log.d(TAG, "用户没有有效的订阅。");
// TODO: 根据您的应用逻辑更新UI或应用状态
// 例如: Constant.subscription = false;
}
} else {
Log.e(TAG, "查询订阅失败: " + billingResult.getDebugMessage());
}
}
);
} else {
Log.e(TAG, "BillingClient 未准备好或为空,无法查询订阅。");
}
}
/**
* 辅助方法:确认购买。
* Google Play 要求所有购买(包括订阅)必须在3天内确认。
* 未确认的购买会在3天后自动退款。
*/
private void acknowledgePurchase(Purchase purchase) {
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.acknowledgePurchase(acknowledgePurchaseParams, billingResult -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
Log.d(TAG, "购买已成功确认: OrderId = " + purchase.getOrderId());
// 确认成功后,可以再次触发订阅状态检查或直接更新UI
// checkSubscriptionStatus(); // 重新检查以更新状态
} else {
Log.e(TAG, "购买确认失败: " + billingResult.getDebugMessage());
}
});
}
// 您可能还需要一个方法来处理可消耗商品的消耗逻辑,如果您的应用有此类商品。
// 订阅商品不需要消耗。
/*
void handleConsumablePurchase(Purchase purchase) {
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(consumeParams, (billingResult, purchaseToken) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
Log.d(TAG, "可消耗商品已成功消耗。");
// TODO: 授予用户商品
} else {
Log.e(TAG, "可消耗商品消耗失败: " + billingResult.getDebugMessage());
}
});
}
*/
}代码解释:
- QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build(): 指定我们只查询订阅类型的商品。
- PurchasesResponseListener: 这是 queryPurchasesAsync 的回调接口,它接收 BillingResult 和一个 Purchase 列表。
- billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK: 检查查询操作本身是否成功。
- purchase.getProducts().contains("your_subscription_product_id"): 这一步至关重要,它确保我们检查的是我们关心的特定订阅商品。务必将 "your_subscription_product_id" 替换为您的实际商品ID。
- purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED: 验证购买的状态是否为“已购买”。
- purchase.isAcknowledged(): 对于所有购买(包括订阅),Google Play 都要求进行确认。如果 isAcknowledged() 返回 false,则需要调用 acknowledgePurchase() 方法进行确认。未确认的购买将在3天后自动退款。
- acknowledgePurchase(purchase): 这是一个辅助方法,用于执行购买确认操作。
何时调用 checkSubscriptionStatus()?
为了确保用户订阅状态的及时性和准确性,您应该在以下关键时刻调用 checkSubscriptionStatus() 方法:
- 应用启动时: 在主 Activity 的 onResume() 方法中或应用初始化流程中调用,确保用户进入应用时,其订阅状态是最新的。
- 从后台返回前台时: 同样可以在 onResume() 中处理,以防用户在应用处于后台期间订阅状态发生变化(例如,订阅到期或在其他设备上取消)。
- 用户尝试访问受限内容时: 在用户尝试访问仅限订阅用户可用的高级功能之前进行检查。
- 网络恢复时: 如果应用在离线状态下启动,当网络连接恢复后,应重新检查订阅状态。
- BillingClient 连接成功后: 确保 BillingClient 已准备就绪且连接成功。
PurchasesUpdatedListener 的角色
虽然 queryPurchasesAsync() 用于查询现有订阅,但 PurchasesUpdatedListener 仍然是处理 新发生购买事件 的关键。当用户完成购买流程(无论是成功、取消还是其他错误)时,此监听器会被触发。
import android.util.Log;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import java.util.List;
public class MyBillingClientLifecycleManager implements PurchasesUpdatedListener {
private SubscriptionManager subscriptionManager; // 假设您有SubscriptionManager实例
public MyBillingClientLifecycleManager(SubscriptionManager manager) {
this.subscriptionManager = manager;
}
@Override
public void onPurchasesUpdated(BillingResult billingResult, List purchases) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
for (Purchase purchase : purchases) {
// 对于新购买的订阅,需要进行确认
if (purchase.getProducts().contains("your_subscription_product_id")) {
// 确认操作应在 SubscriptionManager 中处理
if (!purchase.isAcknowledged()) {
subscriptionManager.acknowledgePurchase(purchase);
}
Log.d("BillingFlow", "新订阅购买成功并处理: OrderId = " + purchase.getOrderId());
// TODO: 更新应用状态,例如 Constant.subscription = true;
}
// 如果是可消耗商品,则需要消耗
// else if (purchase.getProducts().contains("your_consumable_product_id")) {
// subscriptionManager.handleConsumablePurchase(purchase);
// }
}
// 无论新购买成功与否,都建议重新查询一次以同步最新状态
subscriptionManager.checkSubscriptionStatus();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED){
Log.d("BillingFlow", "用户取消了购买流程。");
// TODO: 更新应用状态,例如 Constant.subscription = false;
} else {
Log.e("BillingFlow", "购买流程出现错误: " + billingResult.getDebugMessage());
}
}
} 注意: 订阅商品不需要像可消耗商品那样进行“消耗”。订阅只需在购买后进行一次“确认”即可。原始问题中 handlePurchase 方法中包含的 consumeAsync 逻辑,通常用于处理可消耗商品,不适用于订阅。
重要注意事项与最佳实践
- 购买确认 (Acknowledgement): 这是Google Play Billing中最关键的环节之一。所有购买(包括订阅和非消耗性商品)都必须在购买成功后的3天内通过 acknowledgePurchase() 方法进行确认。如果未在规定时间内确认,Google Play 将自动退款给用户,并且购买会被撤销。
- 服务器端验证: 尽管客户端可以检查订阅状态,但为了防止作弊和提供更强大的安全性,强烈建议在您的后端服务器上










