Google Play结算库V2.0.3 接入实例
package com.android.billing;
import android.app.Activity;
import com.android.billing.util.HookUtil;
import com.android.billing.util.Security;
import com.android.billing.util.Utility;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.ConsumeParams;
import com.android.billingclient.api.ConsumeResponseListener;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Date: 2019/10/15
* Author: anmi
* Desc:google 支付管理类
* 处理与Google Play Store的所有交互(通过计费库),维护与Google Play Store的连接
* 通过BillingClient缓存临时状态/数据
*/
public class BillingManager implements PurchasesUpdatedListener {
/**
* 在BillingManager还没有初始化之前,mBillingClientResponseCode的默认值
*/
public static final int BILLING_MANAGER_NOT_INITIALIZED = -1;
private static final String TAG = BillingManager.class.getSimpleName();
private final static LoggerUtil mLogger;
static {
mLogger = new LoggerUtil();
mLogger.setTag(TAG);
}
/**
* BillingClient 实例对象
**/
private BillingClient mBillingClient;
/**
* 服务连接状态
*/
private boolean mIsServiceConnected;
private final BillingUpdatesListener mBillingUpdatesListener;
private final Activity mActivity;
private final List<Purchase> mPurchases = new ArrayList<>();
private Set<String> mTokensToBeConsumed;
private int mBillingClientResponseCode = BILLING_MANAGER_NOT_INITIALIZED;
/* BASE_64_ENCODED_PUBLIC_KEY should be YOUR APPLICATION'S PUBLIC KEY
* (that you got from the Google Play developer console). This is not your
* developer public key, it's the *app-specific* public key.
*
* Instead of just storing the entire literal string here embedded in the
* program, construct the key at runtime from pieces or
* use bit manipulation (for example, XOR with some other string) to hide
* the actual key. The key itself is not secret information, but we don't
* want to make it easy for an attacker to replace the public key with one
* of their own and then fake messages from the server.
*/
private static final String BASE_64_ENCODED_PUBLIC_KEY = "CONSTRUCT_YOUR";
/**
* 用于监听购买列表完成消费的更新
*/
public interface BillingUpdatesListener {
void onBillingClientSetupFinished();
void onConsumeFinished(BillingResult billingResult, String purchaseToken);
void onPurchasesUpdated(List<Purchase> purchases);
}
/**
* 用于监听 Google Play Store客户端的连接状态
*/
public interface ServiceConnectedListener {
void onServiceConnected(@BillingClient.BillingResponseCode int resultCode);
}
public BillingManager(Activity activity, final BillingUpdatesListener updatesListener) {
mLogger.printDebugLog("Creating Billing client.");
this.mActivity = activity;
this.mBillingUpdatesListener = updatesListener;
//构建BillingClient
mBillingClient = BillingClient.newBuilder(mActivity).setListener(this).enablePendingPurchases().build();
mLogger.printDebugLog("Starting setup.");
/**
*异步启动服务连接Google Play Store客户端
Start setup. This is asynchronous and the specified listener will be called
once setup completes.
It also starts to report all the new purchases through onPurchasesUpdated() callback.
*/
startServiceConnection(new Runnable() {
@Override
public void run() {
//通知购买客户端监听器 通信已就绪
mBillingUpdatesListener.onBillingClientSetupFinished();
//IAB已经建立完成,进行查询我们的库存
mLogger.printDebugLog("Setup successful. Querying inventory.");
queryPurchases();
}
});
}
/**
* 跨应用查询购买信息,并通过监听器返回结果
*/
public void queryPurchases() {
//创建查询任务
Runnable queryToExecute = new Runnable() {
@Override
public void run() {
long time = System.currentTimeMillis();
Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
mLogger.printDebugLog("Querying purchases elapsed time:%s ms", (System.currentTimeMillis() - time));
//如果支持订阅,将添加订阅处理
if (areSubscriptionsSupported()) {
//查询订阅
Purchase.PurchasesResult subscriptionResult
= mBillingClient.queryPurchases(BillingClient.SkuType.SUBS);
mLogger.printDebugLog("Querying purchases and subscriptions elapsed time: %s ms", (System.currentTimeMillis() - time));
mLogger.printDebugLog("Querying subscriptions result code: %s Purchases size: %s", subscriptionResult.getResponseCode(), subscriptionResult.getPurchasesList().size());
if (subscriptionResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
purchasesResult.getPurchasesList().addAll(subscriptionResult.getPurchasesList());
} else {
mLogger.printErrorLog("Got an error response trying to query subscription purchases");
}
} else if (purchasesResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
//跳过订阅购买查询,因为它不受支持
mLogger.printDebugLog("Skipped subscription purchases query since they are not supported");
} else {
mLogger.printDebugLog("queryPurchases() got an error response code: " + purchasesResult.getResponseCode());
}
onQueryPurchasesFinished(purchasesResult);
}
};
//执行查询任务的请求
executeServiceRequest(queryToExecute);
}
/**
* 处理查询购买的结果,并通过监听器通知更新后的列表
*/
private void onQueryPurchasesFinished(Purchase.PurchasesResult result) {
// Have we been disposed of in the meantime? If so, or bad result code, then quit
if (mBillingClient == null || result.getResponseCode() != BillingClient.BillingResponseCode.OK) {
mLogger.printErrorLog("Billing client was null or result code (%s)was bad - quitting", result.getResponseCode());
return;
}
mLogger.printDebugLog("Query inventory was successful.");
// Update the UI and purchases inventory with new list of purchases
mPurchases.clear();
onPurchasesUpdated(result.getBillingResult(), result.getPurchasesList());
}
/**
* 检查当前客户端是否支持订阅
* 注意:此方法不会自动重试RESULT_SERVICE_DISCONNECTED。
* 它只用于queryPurchase执行后, 实现了一个回退机制。
*/
public boolean areSubscriptionsSupported()