android - In App Billing - SKU 在计费过程中为空
问题描述
我正在尝试添加 3 个按钮以在应用程序中购买 3 种不同的东西。
但是,在按下三个按钮中的一个后,虽然可以成功购买第一个产品,但其他两个按钮将不再起作用,无法启动购买过程,甚至重新启动应用程序。按下其他两个按钮的吐司建议说the SKU cannot be null
问题
如何更新代码以使所有 3 个按钮都可以继续购买?
我已经实现了以下内容:
代码详情
IabHelper
班级
public class IabHelper
{
private String TAG = IabHelper.class.getSimpleName();
private Context context;
private BillingClient mBillingClient;
private IAPHelperListener IAPHelperListener;
private List<String> skuList;
* @param context It will be used to get an application context to bind to the in-app billing service.
* @param IAPHelperListener Your listener to get the response for your query.
* @param skuList
public IabHelper(Context context, IAPHelperListener IAPHelperListener, List<String> skuList) {
this.context = context;
this.IAPHelperListener = IAPHelperListener;
this.skuList = skuList;
this.mBillingClient = BillingClient.newBuilder(context)
.enablePendingPurchases()
.setListener(getPurchaseUpdatedListener())
.build();
if (!mBillingClient.isReady()) {
Log.d(TAG, "BillingClient: Start connection...");
startConnection();
}
}
private void startConnection() {
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
int billingResponseCode = billingResult.getResponseCode();
Log.d(TAG, "onBillingSetupFinished: " + billingResult.getResponseCode());
if (billingResponseCode == BillingClient.BillingResponseCode.OK) {
getPurchasedItems();
getSKUDetails(skuList);
}
}
@Override
public void onBillingServiceDisconnected() {
Log.d(TAG, "onBillingServiceDisconnected: ");
}
});
}
public void getPurchasedItems() {
Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
if (IAPHelperListener != null)
IAPHelperListener.onPurchasehistoryResponse(purchasesResult.getPurchasesList());
}
public void getSKUDetails(List<String> skuList) {
final HashMap<String, SkuDetails> skuDetailsHashMap = new HashMap<>();
SkuDetailsParams skuParams = SkuDetailsParams.newBuilder().setType(BillingClient.SkuType.INAPP).setSkusList(skuList).build();
mBillingClient.querySkuDetailsAsync(skuParams, new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
for (SkuDetails skuDetails : skuDetailsList) {
skuDetailsHashMap.put(skuDetails.getSku(), skuDetails);
}
if (IAPHelperListener != null)
IAPHelperListener.onSkuListResponse(skuDetailsHashMap);
}
}
});
}
* @param skuDetails skudetails of the product to be purchased
* Developer console.
public void launchBillingFLow(final SkuDetails skuDetails) {
if(mBillingClient.isReady()){
BillingFlowParams mBillingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build();
mBillingClient.launchBillingFlow((Activity) context, mBillingFlowParams);
}
}
private PurchasesUpdatedListener getPurchaseUpdatedListener()
{
return (billingResult, purchases) -> {
int responseCode = billingResult.getResponseCode();
if (responseCode == BillingClient.BillingResponseCode.OK && purchases != null)
{
//here when purchase completed
for (Purchase purchase : purchases)
{
//For non consumable I will acknowledge purchase
//For consumable I will consume purchase
boolean all_non_consumable = true;
if (all_non_consumable)
{
acknowledgePurchase(purchase); // in marksix all are non consumable
}
else
{
consumePurchase(purchase);
}
}
} else if (responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
Log.d(TAG, "user cancelled");
} else if (responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
Log.d(TAG, "item already owned");
} else if (responseCode == BillingClient.BillingResponseCode.SERVICE_DISCONNECTED) {
Log.d(TAG , "service disconnected");
startConnection();
}
};
}
public void acknowledgePurchase(Purchase purchase)
{
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && isSignatureValid(purchase))
{
//This is for Consumable product
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener()
{
@Override
public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
Log.d("purchase", "Purchase Acknowledged");
}
});
if (IAPHelperListener != null)
IAPHelperListener.onPurchaseCompleted(purchase);
}
}
public void consumePurchase(Purchase purchase) {
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && isSignatureValid(purchase))
{
//This is for Consumable product
ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
mBillingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String s) {
Log.d("purchase", "Purchase Consumed");
}
});
if (IAPHelperListener != null)
IAPHelperListener.onPurchaseCompleted(purchase);
}
}
private boolean isSignatureValid(Purchase purchase) {
return com.pearappx.inappbilling.Security.verifyPurchase(Settings2.base64EncodedPublicKey, purchase.getOriginalJson(), purchase.getSignature());
}
public void endConnection() {
if (mBillingClient != null && mBillingClient.isReady()) {
mBillingClient.endConnection();
mBillingClient = null;
}
}
public interface IAPHelperListener {
void onSkuListResponse(HashMap<String, SkuDetails> skuDetailsHashMap);
void onPurchasehistoryResponse(List<Purchase> purchasedItem);
void onPurchaseCompleted(Purchase purchase);
}
}
`活动课
public class Settings2 extends Activity implements IabHelper.IAPHelperListener
{
IabHelper iapHelper;
HashMap<String, SkuDetails> skuDetailsHashMap = new HashMap<>();
final String ITEM_SKU_10C = "com.10c";
final String ITEM_SKU_15C = "com.15c";
final String ITEM_SKU_20C = "com.20c";
final String TEST = "android.test.purchased"; //This id can be used for testing purpose
private List<String> skuList = Arrays.asList(ITEM_SKU_10C, ITEM_SKU_15C, ITEM_SKU_20C, TEST);
Button buy_10C_Button; //non-consumable (no ad = non-consumable, coins = consumable)
Button buy_15C_Button; //non-consumable
Button buy_20C_Button; //non-consumable
...
public void onCreate(Bundle savedInstanceState)
{
iapHelper = new IabHelper(this, this, skuList);
buy_10C_Button.setOnClickListener(paramAnonymousView -> purchase_action(""+ITEM_SKU_10C));
buy_15C_Button.setOnClickListener(paramAnonymousView -> purchase_action(""+ITEM_SKU_15C));
buy_20C_Button.setOnClickListener(paramAnonymousView -> purchase_action(""+ITEM_SKU_20C));
public void purchase_action(String pur_item)
{
button_pressed = pur_item;
if(!skuDetailsHashMap.isEmpty()) //skuDetailsHashMap is NOT empty
{
iapHelper.launchBillingFLow(skuDetailsHashMap.get(pur_item));
Utilities.system_toast(Settings2.this, "purchase action", "going through");
}
else
{
try
{
Utilities.system_toast(Settings2.this, "purchase action", "nothing happen");
}
catch (Exception ex)
{
Utilities.system_toast(Settings2.this, "purchase action", "ex= " ex.getText.toString());
}
}
}
@Override
public void onSkuListResponse(HashMap<String, SkuDetails> skuDetails)
{
skuDetailsHashMap = skuDetails;
}
@Override
public void onPurchasehistoryResponse(List<Purchase> purchasedItems)
{
if (purchasedItems != null)
{
for (Purchase purchase : purchasedItems)
{
String sku = purchase.getSkus().toString();
countC_upload_parse(sku);
}
}
}
@Override
public void onPurchaseCompleted(Purchase purchase) {
Toast.makeText(getApplicationContext(), "Purchase Successful", Toast.LENGTH_SHORT).show();
String sku = purchase.getSkus().toString();
countC_upload_parse(sku);
}
解决方案
推荐阅读
- python - 优化数据框组 - 滚动 - 应用并添加列回初始数据框
- google-bigquery - 在缺少或没有结果的情况下变平
- python - 使用 Pipenv 拆分包之间的依赖关系
- linux - bash 条件表达式 -x 可以被视为 if 条件吗?
- r - 基于另一个 TIFF 图像重采样多个 .TIFF 图像
- ionic-framework - 地理定位在 Ionic 4 Android 中不起作用
- .net - WinForms RichTextBox将图像保存为无法显示的pngblip
- java - 线程“主”java.io.IOException 中的异常:无法运行程序“”:错误=2,没有这样的文件或目录
- java - 包含子类实例的 Java 集合
- java - 在java中使用扫描仪的麻烦