Google Play 支付文档:https://developer.android.com/google/play/billing/integrate
Google Play 支付库已经升级到5.0了,相对之前的版本有不少的变化,现在记录下!
接入Google Play 流程还是和之前一样:
1.去Google console 申请开发者账号 https://play.google.com/console/
2.创建项目,上传APK
3.去Google console项目后台开始设置商品:点击左侧Products---->In-app products(内购商品)或者Subscription(订阅商品)
4.等Google Pay Console 后台创建好商品后,客户端和后端就可以开始集成了:
4.1:将 Google Play 结算库依赖项添加到应用的
dependencies {
val billing_version = "5.0.0"
implementation("com.android.billingclient:billing:$billing_version")
}
4.2:初始化支付SDK(也就是初始化BillingClient):支付过程中BillingClient用的比较多,一般项目中只创建一个BillingClient
private BillingClient billingClient = BillingClient.newBuilder(context)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
初始化的时候需要一个:PurchasesUpdatedListener,PurchasesUpdatedListener是监听应用中所有购买交易的更新,这个listener非常重要,当用户购买或者订阅后都会走这个回调
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
// To be implemented in a later section.
}
};
4.3初始化SDK后,需要与 Google Play 建立连接,使用startConnection()方法,startConnection是异步进行,这个时候需要一个BillingClientStateListener进行回调连接的结果,当连接完成会走onBillingSetupFinished()回调,通过返回的billingResult.getResponseCode()去判断是否真正的链接成功,这个code 有下面几个值,这个BillingClientStateListener还有一个Google Play 失去连接的回调,这个时候我们需要实现重试逻辑,就是再次调用startConnection()函数。
@Retention(RetentionPolicy.SOURCE)
public @interface BillingResponseCode {
int SERVICE_TIMEOUT = -3;
int FEATURE_NOT_SUPPORTED = -2;
int SERVICE_DISCONNECTED = -1;
int OK = 0;
int USER_CANCELED = 1;
int SERVICE_UNAVAILABLE = 2;
int BILLING_UNAVAILABLE = 3;
int ITEM_UNAVAILABLE = 4;
int DEVELOPER_ERROR = 5;
int ERROR = 6;
int ITEM_ALREADY_OWNED = 7;
int ITEM_NOT_OWNED = 8;
}
public void startConnection() {
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
queryProductDetailsParams();
queryOldOrder();
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
}
4.4 获取商品
当startConnection()回调成功时,这个时候我们就可以根据ProductId去Google Play获取具体的商品了,这个时候一般会通过API去自己的Server 获取一个ProductIdList,然后根据后台返回的productId去Google Play 获取商品详情。
查询内购的商品:
List<String> skuList = new ArrayList<>();
skuList.add("ProductId01");
skuList.add("ProductId02");
skuList.add("ProductId03");
skuList.add("ProductId04");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
mBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
// Process the result.
Log.i(TAG, "querySkuDetailsAsync 1 onSkuDetailsResponse billingResult.getResponseCode : " + billingResult.getResponseCode() + " skuDetailsList :" + skuDetailsList);
mInAppSkuDetailsHashMap.clear();
if (skuDetailsList != null && skuDetailsList.size() > 0) {
for (SkuDetails skuDetails : skuDetailsList) {
mInAppSkuDetailsHashMap.put(skuDetails.getSku(), skuDetails);
}
}
}
});
查询订阅的商品:
// The BillingClient is ready. You can query purchases here.
List<String> subscribeSkuList = new ArrayList<>();
subscribeSkuList.add("Subscribe01");
subscribeSkuList.add("Subscribe01");
subscribeSkuList.add("Subscribe01");
SkuDetailsParams.Builder subscribeParams = SkuDetailsParams.newBuilder();
subscribeParams.setSkusList(subscribeSkuList).setType(BillingClient.SkuType.SUBS);
mBillingClient.querySkuDetailsAsync(subscribeParams.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
// Process the result.
Log.i(TAG, "querySkuDetailsAsync 2 onSkuDetailsResponse billingResult.getResponseCode : " + billingResult.getResponseCode() + " skuDetailsList :" + skuDetailsList);
mSubscribeSkuDetailsHashMap.clear();
if (skuDetailsList != null && skuDetailsList.size() > 0) {
for (SkuDetails skuDetails : skuDetailsList) {
mSubscribeSkuDetailsHashMap.put(skuDetails.getSku(), skuDetails);
}
}
}
});
当商品查询成功后就可以结合Server返回的商品信息给用户展示商品列表了
注意:有些 Android 设备安装的可能是旧版 Google Play 商店应用,不支持订阅等某些商品类型。在您的应用进入结算流程之前,您可以调用 isFeatureSupported() 以确定设备是否支持您要销售的商品。如需查看可支持的商品类型的列表,请参阅 BillingClient.FeatureType。
4.5.启动购买流程(开始购买)
当用户点击某个商品时,从应用发起购买请求,请从应用的主线程调用 launchBillingFlow() 方法。此方法接受对 BillingFlowParams 对象的引用,该对象包含通过调用 queryProductDetailsAsync() 获取的相关 ProductDetails 对象。如需创建 BillingFlowParams
对象,请使用 BillingFlowParams.Builder 类。
购买内购的商品:
public void buyInAppProduct(SkuDetails skuDetails) {
if (skuDetails == null) {
return;
}
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
mBillingClient.launchBillingFlow(ActivityUtils.getTopActivity(), billingFlowParams).getResponseCode();
}
购买订阅的商品:
public void buySubscribeProduct(SkuDetails skuDetails) {
if (skuDetails == null) {
return;
}
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
mBillingClient.launchBillingFlow(ActivityUtils.getTopActivity(), billingFlowParams).getResponseCode();
}
// An activity reference from which the billing flow will be launched.
Activity activity = ...;
ImmutableList productDetailsParamsList =
ImmutableList.of(
ProductDetailsParams.newBuilder()
// retrieve a value for "productDetails" by calling queryProductDetailsAsync()
.setProductDetails(productDetails)
// to get an offer token, call ProductDetails.getSubscriptionOfferDetails()
// for a list of offers that are available to the user
.setOfferToken(selectedOfferToken)
.build()
);
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.build();
// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
4.6购买成功的回调
在咱们4.2初始化SDK的时候添加了一个PurchasesUpdatedListener,当用户购买成功后Google Play 会调用 onPurchasesUpdated(),我们根据
responseCode去区分用户购买成功与否.
如果成功购买商品,系统还会生成一个token,它是一个唯一标识符,表示用户及其所购应用内商品的商品 ID。可以在本地存储token,可以将令牌传递到安全的后端服务器(推荐用该方法)
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
if (billingResult == null) {
return;
}
int responseCode = billingResult.getResponseCode();
switch (responseCode) {
case BillingClient.BillingResponseCode.OK:
for (Purchase purchase : purchases) {
SkuDetails skuDetails = null;
String json = purchase.getOriginalJson();
if (!TextUtils.isEmpty(json)) {
PurchaseData purchaseData = GsonConverter.fromJson(json, PurchaseData.class);
if (purchaseData != null) {
skuDetails = getSkuDetailsDependProductId(purchaseData.getProductId());
}
}
handlePurchase(purchase, (skuDetails != null && (BillingClient.SkuType.SUBS.equals(skuDetails.getType()))), "onPurchasesUpdated");
}
break;
case BillingClient.BillingResponseCode.USER_CANCELED:
Log.i(TAG, "purchasesUpdatedListener 3 user cancel ");
break;
default:
Log.i(TAG, "purchasesUpdatedListener 4 error " + responseCode);
break;
}
}
};
@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingResponseCode.OK
&& purchases != null) {
for (Purchase purchase : purchases) {
handlePurchase(purchase);
}
} else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
4.7.处理购买交易(消费订单)
当用户购买成功后,订单必须消费,如果不消费,三天后Google会自动退款,撤销购买交易。
消费内购的商品:
void handlePurchase(Purchase purchase) {
// Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
Purchase purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant entitlement to the user.
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
ConsumeResponseListener listener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
// Handle the success of the consume operation.
}
}
};
billingClient.consumeAsync(consumeParams, listener);
}
消费订阅商品:订阅的处理方式与非消耗型商品类似。您可以使用 Google Play 结算库中的 BillingClient.acknowledgePurchase() 或 Google Play Developer API 中的 Purchases.Subscriptions.Acknowledge 确认订阅。所有初始订阅购买交易都需要确认。订阅续订不需要确认
BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...
void handlePurchase(Purchase purchase) {
if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
}
}
}
4.8 查询历史订单,消费待处理的交易
public void queryOldOrder() {
mBillingClient.queryPurchasesAsync(BillingClient.SkuType.INAPP, new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
onHandlerQueryPurchases(list, false);
}
}
});
mBillingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS, new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
onHandlerQueryPurchases(list, true);
}
}
});
4.9 处理多件购买交易:
Google Play 允许客户在一笔交易中购买多件相同的应用内商品,只需在购物车中指定商品数量即可(4.0 及更高版本的 Google Play 结算库支持该功能)。应用应根据指定购买数量来处理多件购买并授予权利。注意:多件购买适用于消耗型应用内商品,即可以购买、消耗及再次购买的产品。请勿为不支持重复购买的商品启用该功能。
为了实现多件购买,应用的配置逻辑需要检查商品数量。可以从以下 API 访问 quantity
字段:
- Google Play 结算库中的 getQuantity()。
- Google Play Developer API 中的 Purchases.products.quantity。
添加用于处理多件购买的逻辑后,需要在 Google Play 管理中心的应用内商品管理页面上为相应的商品启用多件购买功能。
注意:请确保应用接受多件购买,然后再在 Play 管理中心启用该功能。您能需要强制更新到提供支持的应用版本,然后才能对商品启用该功能。