升级 Google 内购库

This commit is contained in:
wzq
2023-10-19 17:22:58 +08:00
parent 27713e5300
commit be291fa7e1
8 changed files with 133 additions and 129 deletions

View File

@@ -18,8 +18,8 @@ import android.widget.TextView
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.android.billingclient.api.BillingClient import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingResult import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase import com.android.billingclient.api.Purchase
import com.android.billingclient.api.SkuDetails
import com.appsflyer.AFInAppEventParameterName import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType import com.appsflyer.AFInAppEventType
import com.appsflyer.AppsFlyerLib import com.appsflyer.AppsFlyerLib
@@ -123,7 +123,7 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
ResUtil.getString(R.string.avroom_firstcharge_firstchargedialog_01).toast() ResUtil.getString(R.string.avroom_firstcharge_firstchargedialog_01).toast()
} else if (channel.equals(Constants.GOOGLE)) { } else if (channel.equals(Constants.GOOGLE)) {
goodsList?.get(position)?.let { charge -> goodsList?.get(position)?.let { charge ->
buyProduct(charge.skuDetails) buyProduct(charge.productDetails)
} }
} else { } else {
CommonWebViewActivity.start( CommonWebViewActivity.start(
@@ -142,18 +142,23 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
FirstChargeReward.ONE -> { FirstChargeReward.ONE -> {
spanSize = 6 spanSize = 6
} }
FirstChargeReward.TWO_LEFT -> { FirstChargeReward.TWO_LEFT -> {
spanSize = 3 spanSize = 3
} }
FirstChargeReward.TWO_RIGHT -> { FirstChargeReward.TWO_RIGHT -> {
spanSize = 3 spanSize = 3
} }
FirstChargeReward.THREE -> { FirstChargeReward.THREE -> {
spanSize = 2 spanSize = 2
} }
FirstChargeReward.TWO_LEFT_SMALL -> { FirstChargeReward.TWO_LEFT_SMALL -> {
spanSize = 3 spanSize = 3
} }
FirstChargeReward.TWO_RIGHT_SMALL -> { FirstChargeReward.TWO_RIGHT_SMALL -> {
spanSize = 3 spanSize = 3
} }
@@ -196,11 +201,13 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
binding.rbPlanC.visibility = View.GONE binding.rbPlanC.visibility = View.GONE
binding.rbPlanA.text = "$${goodsList[0].chargeMoney}" binding.rbPlanA.text = "$${goodsList[0].chargeMoney}"
} }
2 -> { 2 -> {
binding.rbPlanC.visibility = View.GONE binding.rbPlanC.visibility = View.GONE
binding.rbPlanA.text = "$${goodsList[0].chargeMoney}" binding.rbPlanA.text = "$${goodsList[0].chargeMoney}"
binding.rbPlanB.text = "$${goodsList[1].chargeMoney}" binding.rbPlanB.text = "$${goodsList[1].chargeMoney}"
} }
3 -> { 3 -> {
binding.rbPlanA.text = "$${goodsList[0].chargeMoney}" binding.rbPlanA.text = "$${goodsList[0].chargeMoney}"
binding.rbPlanB.text = "$${goodsList[1].chargeMoney}" binding.rbPlanB.text = "$${goodsList[1].chargeMoney}"
@@ -227,20 +234,19 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
for (bean in goodsList) { for (bean in goodsList) {
productKeys.add(bean.chargeProdId) productKeys.add(bean.chargeProdId)
} }
billingManager?.querySkuDetailsAsync( billingManager?.querySkuDetailsAsync(productKeys) { billingResult: BillingResult, productDetails: MutableList<ProductDetails> ->
BillingClient.SkuType.INAPP, productKeys
) { billingResult: BillingResult, skuDetailsList: List<SkuDetails>? ->
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) { if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
Log.w( Log.w(
TAG, TAG,
"Unsuccessful query for type: " + BillingClient.SkuType.INAPP "Unsuccessful query for type: " + BillingClient.ProductType.INAPP + ". Error code: " + billingResult.responseCode
+ ". Error code: " + billingResult.responseCode
) )
} else if (skuDetailsList != null && skuDetailsList.isNotEmpty()) { return@querySkuDetailsAsync
}
if (productDetails.isNotEmpty()) {
for (chargeBean in goodsList) { for (chargeBean in goodsList) {
for (skuDetails in skuDetailsList) { for (skuDetails in productDetails) {
if (skuDetails.sku == chargeBean.chargeProdId) { if (skuDetails.productId == chargeBean.chargeProdId) {
chargeBean.skuDetails = skuDetails chargeBean.productDetails = skuDetails
break break
} }
} }
@@ -258,7 +264,7 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
) { ) {
PayModel.get().verifyOrder( PayModel.get().verifyOrder(
purchase.accountIdentifiers!!.obfuscatedAccountId, purchase.accountIdentifiers!!.obfuscatedAccountId,
purchase.skus[0], purchase.products[0],
purchase.packageName, purchase.packageName,
purchase.purchaseToken purchase.purchaseToken
) )
@@ -267,12 +273,12 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
{ token: String? -> { token: String? ->
//L.i("token=" + token); //L.i("token=" + token);
billingManager?.consumeAsync(token) billingManager?.consumeAsync(token)
var skuDetails: SkuDetails? = null var skuDetails: ProductDetails? = null
val goodList = goodsList val goodList = goodsList
if (goodList != null && goodList.isNotEmpty()) { if (!goodList.isNullOrEmpty()) {
for (datum in goodList) { for (datum in goodList) {
if (datum.chargeProdId == purchase.skus[0]) { if (datum.chargeProdId == purchase.products[0]) {
skuDetails = datum.skuDetails skuDetails = datum.productDetails
break break
} }
} }
@@ -282,12 +288,12 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
HashMap() HashMap()
eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold" eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold"
eventValue[AFInAppEventParameterName.QUANTITY] = 1 eventValue[AFInAppEventParameterName.QUANTITY] = 1
eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.orderId eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.orderId!!
eventValue[AFInAppEventParameterName.REVENUE] = eventValue[AFInAppEventParameterName.REVENUE] =
skuDetails.priceAmountMicros / 1000000f skuDetails.oneTimePurchaseOfferDetails?.priceAmountMicros!! / 1000000f
eventValue["Price"] = skuDetails.price eventValue["Price"] = skuDetails.oneTimePurchaseOfferDetails?.formattedPrice!!
eventValue[AFInAppEventParameterName.CURRENCY] = eventValue[AFInAppEventParameterName.CURRENCY] =
skuDetails.priceCurrencyCode skuDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode!!
AppsFlyerLib.getInstance().logEvent( AppsFlyerLib.getInstance().logEvent(
applicationContext, applicationContext,
AFInAppEventType.PURCHASE, AFInAppEventType.PURCHASE,
@@ -315,10 +321,10 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
/*购买商品*/ /*购买商品*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
fun buyProduct(skuDetails: SkuDetails?) { fun buyProduct(skuDetails: ProductDetails?) {
if (skuDetails != null) { if (skuDetails != null) {
Log.d(TAG, "BuyProduct:" + skuDetails.sku) Log.d(TAG, "BuyProduct:" + skuDetails.productId)
PayModel.get().placeOrder(skuDetails.sku) PayModel.get().placeOrder(skuDetails.productId)
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
{ recordId: PayRecordId -> { recordId: PayRecordId ->
@@ -372,6 +378,7 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
bean.itemType = FirstChargeReward.ONE bean.itemType = FirstChargeReward.ONE
} }
} }
2 -> { 2 -> {
for (i in firstChargeRewardList.indices) { for (i in firstChargeRewardList.indices) {
if (i == 0) { if (i == 0) {
@@ -381,11 +388,13 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
} }
} }
} }
3 -> { 3 -> {
for (bean in firstChargeRewardList) { for (bean in firstChargeRewardList) {
bean.itemType = FirstChargeReward.THREE bean.itemType = FirstChargeReward.THREE
} }
} }
4 -> { 4 -> {
for (i in firstChargeRewardList.indices) { for (i in firstChargeRewardList.indices) {
if ((i + 1) % 2 != 0) { if ((i + 1) % 2 != 0) {
@@ -395,6 +404,7 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
} }
} }
} }
else -> { else -> {
if (firstChargeRewardList.size % 3 == 0) { if (firstChargeRewardList.size % 3 == 0) {
for (bean in firstChargeRewardList) { for (bean in firstChargeRewardList) {

View File

@@ -3,28 +3,20 @@ package com.yizhuan.erban.ui.pay;
import android.app.Activity; import android.app.Activity;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.android.billingclient.api.AcknowledgePurchaseParams;
import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClient.BillingResponseCode; import com.android.billingclient.api.BillingClient.BillingResponseCode;
import com.android.billingclient.api.BillingClient.SkuType;
import com.android.billingclient.api.BillingClientStateListener; import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeParams;
import com.android.billingclient.api.ConsumeResponseListener; import com.android.billingclient.api.ProductDetails;
import com.android.billingclient.api.ProductDetailsResponseListener;
import com.android.billingclient.api.Purchase; import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.Purchase.PurchasesResult;
import com.android.billingclient.api.PurchasesUpdatedListener; import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.QueryProductDetailsParams;
import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.QueryPurchasesParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.yizhuan.erban.event.ChargeEvent;
import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
@@ -109,25 +101,23 @@ public class BillingManager implements PurchasesUpdatedListener {
/*请求商品库存*/ /*请求商品库存*/
public void onQueryPurchases() { public void onQueryPurchases() {
Runnable queryToExecute = () -> { Runnable queryToExecute = () ->
//系统当前时间 billingClient.queryPurchasesAsync(
long time = System.currentTimeMillis(); QueryPurchasesParams.newBuilder()
//请求内购商品 .setProductType(BillingClient.ProductType.INAPP)
PurchasesResult purchasesResult = billingClient.queryPurchases(SkuType.INAPP); .build(), this::onQueryPurchasesFinished);
onQueryPurchasesFinished(purchasesResult);
};
executeServiceRequest(queryToExecute); executeServiceRequest(queryToExecute);
} }
/*请求商品信息完成*/ /*请求商品信息完成*/
private void onQueryPurchasesFinished(PurchasesResult result) { private void onQueryPurchasesFinished(BillingResult result, List<Purchase> list) {
if (billingClient == null || result.getResponseCode() != BillingResponseCode.OK) { if (billingClient == null || result.getResponseCode() != BillingResponseCode.OK) {
Log.w(TAG, "billingClient is null or result code (" + result.getResponseCode() Log.w(TAG, "billingClient is null or result code (" + result.getResponseCode()
+ ") was bad - quitting"); + ") was bad - quitting");
return; return;
} }
purchaseList.clear(); purchaseList.clear();
onPurchasesUpdated(result.getBillingResult(), result.getPurchasesList()); onPurchasesUpdated(result, list);
} }
/*更新商品*/ /*更新商品*/
@@ -178,28 +168,46 @@ public class BillingManager implements PurchasesUpdatedListener {
} }
/*查询内购商品详情*/ /*查询内购商品详情*/
public void querySkuDetailsAsync(@SkuType final String itemType, final List<String> skuList, public void querySkuDetailsAsync(final List<String> productIdList,
final SkuDetailsResponseListener listener) { final ProductDetailsResponseListener listener) {
Runnable queryRequest = () -> { Runnable queryRequest = () -> {
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); ArrayList<QueryProductDetailsParams.Product> products = new ArrayList<>();
params.setSkusList(skuList) for (String productId : productIdList) {
.setType(itemType); products.add(QueryProductDetailsParams.Product.newBuilder()
billingClient.querySkuDetailsAsync(params.build(), listener); .setProductId(productId)
.setProductType(BillingClient.ProductType.INAPP)
.build());
}
QueryProductDetailsParams queryProductDetailsParams =
QueryProductDetailsParams.newBuilder()
.setProductList(products)
.build();
billingClient.queryProductDetailsAsync(
queryProductDetailsParams,
listener
);
}; };
executeServiceRequest(queryRequest); executeServiceRequest(queryRequest);
} }
/*启动购买,订购流程*/ /*启动购买,订购流程*/
public void initiatePurchaseFlow(final SkuDetails skuDetails, String recordId) { public void initiatePurchaseFlow(final ProductDetails productDetails, String recordId) {
Runnable purchaseFlowRequest = () -> { Runnable purchaseFlowRequest = () -> {
BillingFlowParams.ProductDetailsParams p = BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build();
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("p", skuDetails.getPrice()); ProductDetails.OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails = productDetails.getOneTimePurchaseOfferDetails();
jsonObject.put("a", skuDetails.getPriceAmountMicros() / 10000); if (oneTimePurchaseOfferDetails != null) {
jsonObject.put("c", skuDetails.getPriceCurrencyCode()); jsonObject.put("p", oneTimePurchaseOfferDetails.getFormattedPrice());
jsonObject.put("a", oneTimePurchaseOfferDetails.getPriceAmountMicros() / 10000);
jsonObject.put("c", oneTimePurchaseOfferDetails.getPriceCurrencyCode());
}
BillingFlowParams purchaseParams = BillingFlowParams.newBuilder() BillingFlowParams purchaseParams = BillingFlowParams.newBuilder()
.setObfuscatedAccountId(recordId) .setObfuscatedAccountId(recordId)
.setObfuscatedProfileId(jsonObject.toJSONString()) .setObfuscatedProfileId(jsonObject.toJSONString())
.setSkuDetails(skuDetails) .setProductDetailsParamsList(List.of(p))
.build(); .build();
BillingResult billingResult = billingClient.launchBillingFlow(mActivity, purchaseParams); BillingResult billingResult = billingClient.launchBillingFlow(mActivity, purchaseParams);
Log.i(TAG, " initiatePurchaseFlow billingResult=" + billingResult.getResponseCode() + " " + billingResult.getDebugMessage()); Log.i(TAG, " initiatePurchaseFlow billingResult=" + billingResult.getResponseCode() + " " + billingResult.getDebugMessage());
@@ -218,18 +226,8 @@ public class BillingManager implements PurchasesUpdatedListener {
final ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken).build(); final ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken).build();
final ConsumeResponseListener consumeResponseListener = new ConsumeResponseListener() { executeServiceRequest(() -> billingClient.consumeAsync(consumeParams, (billingResult, s) ->
@Override mBillingUpdatesListener.onConsumeFinished(purchaseToken, billingResult.getResponseCode())));
public void onConsumeResponse(@NonNull @NotNull BillingResult billingResult, @NonNull @NotNull String s) {
mBillingUpdatesListener.onConsumeFinished(purchaseToken, billingResult.getResponseCode());
}
};
executeServiceRequest(() -> billingClient.consumeAsync(consumeParams, consumeResponseListener));
}
public void acknowledgePurchase(AcknowledgePurchaseParams acknowledgePurchaseParams, AcknowledgePurchaseResponseListener Listener) {
billingClient.acknowledgePurchase(acknowledgePurchaseParams, Listener);
} }
/** /**

View File

@@ -24,8 +24,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.ProductDetails;
import com.android.billingclient.api.Purchase; import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.SkuDetails;
import com.appsflyer.AFInAppEventParameterName; import com.appsflyer.AFInAppEventParameterName;
import com.appsflyer.AFInAppEventType; import com.appsflyer.AFInAppEventType;
import com.appsflyer.AppsFlyerLib; import com.appsflyer.AppsFlyerLib;
@@ -186,19 +186,19 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
productKeys.add(chargeBean.getChargeProdId()); productKeys.add(chargeBean.getChargeProdId());
} }
mChargeAdapter.setNewData(chargeBeanList); mChargeAdapter.setNewData(chargeBeanList);
billingManager.querySkuDetailsAsync(BillingClient.SkuType.INAPP, productKeys, (billingResult, skuDetailsList) -> { billingManager.querySkuDetailsAsync(productKeys, (billingResult, productDetails) -> {
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
Log.w(TAG, "Unsuccessful query for type: " + BillingClient.SkuType.INAPP Log.w(TAG, "Unsuccessful query for type: " + BillingClient.ProductType.INAPP
+ ". Error code: " + billingResult.getResponseCode()); + ". Error code: " + billingResult.getResponseCode());
getDialogManager().dismissDialog(); getDialogManager().dismissDialog();
toast(getString(R.string.Recharge_failure)); toast(getString(R.string.Recharge_failure));
} else if (skuDetailsList != null && skuDetailsList.size() > 0) { } else if (productDetails.size() > 0) {
getDialogManager().dismissDialog(); getDialogManager().dismissDialog();
List<ChargeBean> showChargeList = new ArrayList<>(); List<ChargeBean> showChargeList = new ArrayList<>();
for (ChargeBean chargeBean : chargeBeanList) { for (ChargeBean chargeBean : chargeBeanList) {
for (SkuDetails skuDetails : skuDetailsList) { for (ProductDetails product : productDetails) {
if (skuDetails.getSku().equals(chargeBean.getChargeProdId())) { if (product.getProductId().equals(chargeBean.getChargeProdId())) {
chargeBean.setSkuDetails(skuDetails); chargeBean.setProductDetails(product);
showChargeList.add(chargeBean); showChargeList.add(chargeBean);
break; break;
} }
@@ -221,30 +221,28 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
purchase.getAccountIdentifiers() != null) { purchase.getAccountIdentifiers() != null) {
PayModel.get().verifyOrder( PayModel.get().verifyOrder(
purchase.getAccountIdentifiers().getObfuscatedAccountId(), purchase.getAccountIdentifiers().getObfuscatedAccountId(),
purchase.getSkus().get(0), purchase.getProducts().get(0),
purchase.getPackageName(), purchase.getPackageName(),
purchase.getPurchaseToken()) purchase.getPurchaseToken())
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(token -> {
token -> {
//L.i("token=" + token);
billingManager.consumeAsync(token); billingManager.consumeAsync(token);
SkuDetails skuDetails = null; ProductDetails productDetails = null;
for (ChargeBean datum : mChargeAdapter.getData()) { for (ChargeBean datum : mChargeAdapter.getData()) {
if (datum.getChargeProdId().equals(purchase.getSkus().get(0))) { if (datum.getChargeProdId().equals(purchase.getProducts().get(0))) {
skuDetails = datum.getSkuDetails(); productDetails = datum.getProductDetails();
break; break;
} }
} }
if (skuDetails != null) { if (productDetails != null) {
Map<String, Object> eventValue = new HashMap<>(); Map<String, Object> eventValue = new HashMap<>();
eventValue.put(AFInAppEventParameterName.CONTENT_TYPE, "Gold"); eventValue.put(AFInAppEventParameterName.CONTENT_TYPE, "Gold");
eventValue.put(AFInAppEventParameterName.QUANTITY, 1); eventValue.put(AFInAppEventParameterName.QUANTITY, 1);
eventValue.put(AFInAppEventParameterName.CONTENT_ID, purchase.getOrderId()); eventValue.put(AFInAppEventParameterName.CONTENT_ID, purchase.getOrderId());
eventValue.put(AFInAppEventParameterName.REVENUE, skuDetails.getPriceAmountMicros() / 1000000f); eventValue.put(AFInAppEventParameterName.REVENUE, productDetails.getOneTimePurchaseOfferDetails().getPriceAmountMicros() / 1000000f);
eventValue.put("Price", skuDetails.getPrice()); eventValue.put("Price", productDetails.getOneTimePurchaseOfferDetails().getFormattedPrice());
eventValue.put(AFInAppEventParameterName.CURRENCY, skuDetails.getPriceCurrencyCode()); eventValue.put(AFInAppEventParameterName.CURRENCY, productDetails.getOneTimePurchaseOfferDetails().getPriceCurrencyCode());
AppsFlyerLib.getInstance().logEvent(getApplicationContext(), AFInAppEventType.PURCHASE, eventValue); AppsFlyerLib.getInstance().logEvent(getApplicationContext(), AFInAppEventType.PURCHASE, eventValue);
} }
}, },
@@ -269,12 +267,12 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
/*购买商品*/ /*购买商品*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
public void buyProduct(SkuDetails skuDetails) { public void buyProduct(ProductDetails productDetails) {
if (skuDetails != null) { if (productDetails != null) {
Log.d(TAG, "BuyProduct:" + skuDetails.getSku()); Log.d(TAG, "BuyProduct:" + productDetails.getProductId());
PayModel.get().placeOrder(skuDetails.getSku()) PayModel.get().placeOrder(productDetails.getProductId())
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe(recordId -> billingManager.initiatePurchaseFlow(skuDetails, recordId.getRecordId()), .subscribe(recordId -> billingManager.initiatePurchaseFlow(productDetails, recordId.getRecordId()),
throwable -> { throwable -> {
if (throwable instanceof FailReasonException) { if (throwable instanceof FailReasonException) {
FailReasonException failReasonException = (FailReasonException) throwable; FailReasonException failReasonException = (FailReasonException) throwable;
@@ -342,8 +340,8 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
} }
if (mChargePosition != -1) { if (mChargePosition != -1) {
ChargeBean bean = mChargeAdapter.getItem(mChargePosition); ChargeBean bean = mChargeAdapter.getItem(mChargePosition);
if (bean != null && bean.getSkuDetails() != null) { if (bean != null && bean.getProductDetails() != null) {
buyProduct(bean.getSkuDetails()); buyProduct(bean.getProductDetails());
//点击充值 //点击充值
HashMap<String, Object> map = new HashMap<>(3); HashMap<String, Object> map = new HashMap<>(3);
map.put(IReportConstants.MONEY, bean.money); map.put(IReportConstants.MONEY, bean.money);

View File

@@ -21,8 +21,8 @@ public class ChargeAdapter extends BaseQuickAdapter<ChargeBean, BaseViewHolder>
if (chargeBean == null) return; if (chargeBean == null) return;
baseViewHolder.getView(R.id.ll_bg).setSelected(chargeBean.isSelected); baseViewHolder.getView(R.id.ll_bg).setSelected(chargeBean.isSelected);
baseViewHolder.setText(R.id.tv_title, chargeBean.getProdName()); baseViewHolder.setText(R.id.tv_title, chargeBean.getProdName());
if (chargeBean.getSkuDetails() != null) { if (chargeBean.getProductDetails() != null) {
baseViewHolder.setText(R.id.item_charge_money, chargeBean.getSkuDetails().getPrice()); baseViewHolder.setText(R.id.item_charge_money, chargeBean.getProductDetails().getOneTimePurchaseOfferDetails().getFormattedPrice());
} else { } else {
baseViewHolder.setText(R.id.item_charge_money, "USD$" + chargeBean.getMoney()); baseViewHolder.setText(R.id.item_charge_money, "USD$" + chargeBean.getMoney());
} }

View File

@@ -14,8 +14,8 @@ import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.android.billingclient.api.BillingClient import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingResult import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase import com.android.billingclient.api.Purchase
import com.android.billingclient.api.SkuDetails
import com.appsflyer.AFInAppEventParameterName import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType import com.appsflyer.AFInAppEventType
import com.appsflyer.AppsFlyerLib import com.appsflyer.AppsFlyerLib
@@ -233,12 +233,12 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
binding.tvOpenVip.setOnClickListener { binding.tvOpenVip.setOnClickListener {
if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) {
if ((googleChargeBean?.skuDetails?.price ?: "0") == "0") { if ((googleChargeBean?.productDetails?.oneTimePurchaseOfferDetails?.priceAmountMicros ?: "0") == "0") {
toast(getString(R.string.Recharge_failure)) toast(getString(R.string.Recharge_failure))
return@setOnClickListener return@setOnClickListener
} }
SelectPayTypeDialog.newInstance( SelectPayTypeDialog.newInstance(
googleChargeBean?.skuDetails?.price ?: "0", googleChargeBean?.productDetails?.oneTimePurchaseOfferDetails?.formattedPrice ?: "0",
true, true,
googleChargeBean?.getMoney() ?: 0.0 googleChargeBean?.getMoney() ?: 0.0
) )
@@ -248,7 +248,7 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
} }
setOnGoogleChargeClick { setOnGoogleChargeClick {
googleChargeBean?.let { charge -> googleChargeBean?.let { charge ->
buyProduct(charge.skuDetails) buyProduct(charge.productDetails)
} }
} }
setOnChargeClick { setOnChargeClick {
@@ -396,20 +396,18 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
chargeInfo?.let { chargeBean -> chargeInfo?.let { chargeBean ->
val productKeys: MutableList<String> = ArrayList() val productKeys: MutableList<String> = ArrayList()
productKeys.add(chargeBean.getChargeProdId()) productKeys.add(chargeBean.getChargeProdId())
billingManager?.querySkuDetailsAsync( billingManager?.querySkuDetailsAsync(productKeys) { billingResult: BillingResult, productDetails: List<ProductDetails> ->
BillingClient.SkuType.INAPP, productKeys
) { billingResult: BillingResult, skuDetailsList: List<SkuDetails>? ->
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) { if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
Log.w( Log.w(
TAG, TAG,
"Unsuccessful query for type: " + BillingClient.SkuType.INAPP "Unsuccessful query for type: " + BillingClient.SkuType.INAPP
+ ". Error code: " + billingResult.responseCode + ". Error code: " + billingResult.responseCode
) )
} else if (skuDetailsList != null && skuDetailsList.isNotEmpty()) { } else if (productDetails.isNotEmpty()) {
val showChargeList: MutableList<ChargeBean> = ArrayList() val showChargeList: MutableList<ChargeBean> = ArrayList()
for (skuDetails in skuDetailsList) { for (skuDetails in productDetails) {
if (skuDetails.sku == chargeBean.getChargeProdId()) { if (skuDetails.productId == chargeBean.getChargeProdId()) {
chargeBean.skuDetails = skuDetails chargeBean.productDetails = skuDetails
showChargeList.add(chargeBean) showChargeList.add(chargeBean)
break break
} }
@@ -439,7 +437,7 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
) { ) {
PayModel.get().verifyOrder( PayModel.get().verifyOrder(
purchase.accountIdentifiers!!.obfuscatedAccountId, purchase.accountIdentifiers!!.obfuscatedAccountId,
purchase.skus[0], purchase.products[0],
purchase.packageName, purchase.packageName,
purchase.purchaseToken purchase.purchaseToken
) )
@@ -448,21 +446,21 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
{ token: String? -> { token: String? ->
//L.i("token=" + token); //L.i("token=" + token);
billingManager?.consumeAsync(token) billingManager?.consumeAsync(token)
var skuDetails: SkuDetails? = null var skuDetails: ProductDetails? = null
if (googleChargeBean?.getChargeProdId() == purchase.skus[0]) { if (googleChargeBean?.getChargeProdId() == purchase.products[0]) {
skuDetails = googleChargeBean?.skuDetails skuDetails = googleChargeBean?.productDetails
} }
if (skuDetails != null) { if (skuDetails != null) {
val eventValue: MutableMap<String, Any> = val eventValue: MutableMap<String, Any> =
HashMap() HashMap()
eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold" eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold"
eventValue[AFInAppEventParameterName.QUANTITY] = 1 eventValue[AFInAppEventParameterName.QUANTITY] = 1
eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.orderId eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.orderId!!
eventValue[AFInAppEventParameterName.REVENUE] = eventValue[AFInAppEventParameterName.REVENUE] =
skuDetails.priceAmountMicros / 1000000f skuDetails.oneTimePurchaseOfferDetails?.priceAmountMicros!! / 1000000f
eventValue["Price"] = skuDetails.price eventValue["Price"] = skuDetails.oneTimePurchaseOfferDetails?.formattedPrice!!
eventValue[AFInAppEventParameterName.CURRENCY] = eventValue[AFInAppEventParameterName.CURRENCY] =
skuDetails.priceCurrencyCode skuDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode!!
AppsFlyerLib.getInstance().logEvent( AppsFlyerLib.getInstance().logEvent(
applicationContext, applicationContext,
AFInAppEventType.PURCHASE, AFInAppEventType.PURCHASE,
@@ -490,15 +488,15 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
/*购买商品*/ /*购买商品*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
fun buyProduct(skuDetails: SkuDetails?) { fun buyProduct(productDetails: ProductDetails?) {
if (skuDetails != null) { if (productDetails != null) {
Log.d(TAG, "BuyProduct:" + skuDetails.sku) Log.d(TAG, "BuyProduct:" + productDetails.productId)
PayModel.get().placeOrder(skuDetails.sku) PayModel.get().placeOrder(productDetails.productId)
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
{ recordId: PayRecordId -> { recordId: PayRecordId ->
billingManager?.initiatePurchaseFlow( billingManager?.initiatePurchaseFlow(
skuDetails, productDetails,
recordId.recordId recordId.recordId
) )
} }

View File

@@ -95,8 +95,8 @@ dependencies {
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
//googleplay内购 //googleplay内购
api 'com.google.android.gms:play-services-wallet:19.1.0' api 'com.google.android.gms:play-services-wallet:19.2.1'
api 'com.android.billingclient:billing:4.1.0' api 'com.android.billingclient:billing:6.0.1'
api 'org.jetbrains.kotlin:kotlin-reflect:1.7.10' api 'org.jetbrains.kotlin:kotlin-reflect:1.7.10'

View File

@@ -1,6 +1,6 @@
package com.yizhuan.xchat_android_core.pay.bean; package com.yizhuan.xchat_android_core.pay.bean;
import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.ProductDetails;
import java.io.Serializable; import java.io.Serializable;
@@ -25,7 +25,7 @@ public class ChargeBean implements Serializable{
public int giftGoldNum; public int giftGoldNum;
public int channel; public int channel;
public String prodDesc; public String prodDesc;
private SkuDetails skuDetails; private ProductDetails mProductDetails;
public boolean isSelected; public boolean isSelected;
@@ -82,12 +82,12 @@ public class ChargeBean implements Serializable{
this.prodDesc = prodDesc; this.prodDesc = prodDesc;
} }
public SkuDetails getSkuDetails() { public ProductDetails getProductDetails() {
return skuDetails; return mProductDetails;
} }
public void setSkuDetails(SkuDetails skuDetails) { public void setProductDetails(ProductDetails productDetails) {
this.skuDetails = skuDetails; this.mProductDetails = productDetails;
} }
public boolean isSelected() { public boolean isSelected() {
@@ -107,7 +107,7 @@ public class ChargeBean implements Serializable{
", giftGoldNum=" + giftGoldNum + ", giftGoldNum=" + giftGoldNum +
", channel=" + channel + ", channel=" + channel +
", prodDesc='" + prodDesc + '\'' + ", prodDesc='" + prodDesc + '\'' +
", skuDetails=" + skuDetails + ", productDetails=" + mProductDetails +
", isSelected=" + isSelected + ", isSelected=" + isSelected +
'}'; '}';
} }

View File

@@ -1,6 +1,6 @@
package com.yizhuan.xchat_android_core.pay.bean; package com.yizhuan.xchat_android_core.pay.bean;
import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.ProductDetails;
import java.util.ArrayList; import java.util.ArrayList;
@@ -17,5 +17,5 @@ public class FirstChargeGoods {
private ArrayList<FirstChargeReward> firstChargeRewardList; private ArrayList<FirstChargeReward> firstChargeRewardList;
private String giveMoney; private String giveMoney;
private boolean finishCharge; private boolean finishCharge;
private SkuDetails skuDetails; private ProductDetails productDetails;
} }