I was using google app billing v3. I upgraded it to v4. GetSku() gave an error when I upgraded.
Doing this with getSkus() and "purchase.getSkus().contains(getResources().getString(R.string.Product_ID)) && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED" fixed the error.
When I click and open the premium purchase page for the first time, the products and prices do not appear. When I leave the page and enter the 2nd and 3rd time, the products and prices appear. Both in-app product selling and subscription part have the same problem. The codes are the same. I was not having this issue in v3. I had this problem after upgrading to v4. Where could the problem be?
private BillingClient billingClient;
ConsumeResponseListener listener ;
RecyclerView recyclerView;
Context context = this;
recyclerView = findViewById(R.id.recyler_product);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
recyclerView.setLayoutManager(layoutManager);
setupBillingClient();
private void loadProductToRecyclerView(List<SkuDetails> list) {
MyProductAdapter adapter = new MyProductAdapter(this,list,billingClient);
recyclerView.setAdapter(adapter);
}
private void setupBillingClient() {
listener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String s) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
{
// "Consume OK"
}
}
};
billingClient = BillingClientSetup.getInstance(this,this);
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
{
// "Succes to connect billing"
List<Purchase> purchases = billingClient.queryPurchases(BillingClient.SkuType.INAPP)
.getPurchasesList();
handleItemAlreadyPuchase(purchases);
loadAllPurchasePackage();
}
else
Toast.makeText(context,
billingResult.getResponseCode(), Toast.LENGTH_SHORT).show();
}
@Override
public void onBillingServiceDisconnected() {
Toast.makeText(context, "Failed", Toast.LENGTH_SHORT).show();
}
});
}
public void loadAllPurchasePackage(){
if (billingClient.isReady())
{
SkuDetailsParams params= SkuDetailsParams.newBuilder()
.setSkusList(Arrays.asList("product_example_1","product_example_2","product_example_3"))
.setType(BillingClient.SkuType.INAPP)
.build();
billingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
{
loadProductToRecyclerView(list);
}
else
Toast.makeText(context, "Failed:"+billingResult.getResponseCode(), Toast.LENGTH_SHORT).show();
}
});
}
}
private void handleItemAlreadyPuchase(List<Purchase> purchases) {
StringBuilder purchasedItem = new StringBuilder(txtpremium.getText()); // empty
for (Purchase purchase : purchases)
{
// if (purchase.getSku().equals("product_example_1")) // consume item
// if (purchase.getSkus().equals("product_example_1")) // consume item
if (purchase.getSkus().contains(getResources().getString(R.string.Product_ID)) && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) // consume item
{
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(consumeParams,listener);
product1savedatabase();
}
// if (purchase.getSku().equals("product_example_2")) // consume item
if (purchase.getSkus().contains(getResources().getString(R.string.Product_ID2)) && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) // consume item
{
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(consumeParams,listener);
product2savedatabase();
}
// purchasedItem.append("\n"+purchase.getSku())
purchasedItem.append("\n"+purchase.getSkus()).append("\n");
}
txtpremium.setVisibility(View.VISIBLE);
}
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
&& list != null){
handleItemAlreadyPuchase(list);
}
else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED)
Toast.makeText(this, "Purchase canceled
", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "Failed:"+billingResult.getResponseCode(), Toast.LENGTH_SHORT).show();
}
MyProductAdapter :
public class MyProductAdapter extends RecyclerView.Adapter<MyProductAdapter .MyViewHolder> {
AppCompatActivity appCompatActivity ;
List<SkuDetails> skuDetailsList;
BillingClient billingClient;
public MyProductAdapter (AppCompatActivity appCompatActivity, List<SkuDetails> skuDetailsList, BillingClient billingClient) {
this.appCompatActivity = appCompatActivity;
this.skuDetailsList = skuDetailsList;
this.billingClient = billingClient;
}
@NonNull
@Override
public MyProductAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
return new MyProductAdapter.MyViewHolder(LayoutInflater.from(appCompatActivity.getBaseContext())
.inflate(R.layout.layout_product_display,parent,false));
}
@Override
public void onBindViewHolder(@NonNull MyProductAdapter.MyViewHolder myViewHolder, int position) {
myViewHolder.txt_product_name.setText(skuDetailsList.get(position).getTitle().substring(0,8));
myViewHolder.txt_price.setText(skuDetailsList.get(position).getPrice());
myViewHolder.setListener(new IRecylerClickListener() {
@Override
public void onClick(View view, int position) {
// //Launch billing flow
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList.get(position))
.build();
int reponse = billingClient.launchBillingFlow(appCompatActivity,billingFlowParams)
.getResponseCode();
switch (reponse)
{
case BillingClient.BillingResponseCode.BILLING_UNAVAILABLE:
Toast.makeText(appCompatActivity, "BILLING UNAVAILABLE", Toast.LENGTH_LONG).show();
break;
case BillingClient.BillingResponseCode.DEVELOPER_ERROR:
Toast.makeText(appCompatActivity, "DEVELOPER ERROR", Toast.LENGTH_LONG).show();
break;
case BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED:
Toast.makeText(appCompatActivity, "FEATURE NOT SUPPORTED", Toast.LENGTH_LONG).show();
break;
case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED:
Toast.makeText(appCompatActivity, "ITEM ALREADY OWNED", Toast.LENGTH_LONG).show();
break;
case BillingClient.BillingResponseCode.SERVICE_DISCONNECTED:
Toast.makeText(appCompatActivity, "SERVICE DISCONNECTED", Toast.LENGTH_LONG).show();
break;
case BillingClient.BillingResponseCode.SERVICE_TIMEOUT:
Toast.makeText(appCompatActivity, "SERVICE TIMEOUT", Toast.LENGTH_LONG).show();
break;
case BillingClient.BillingResponseCode.ITEM_UNAVAILABLE:
Toast.makeText(appCompatActivity, "ITEM UNAVAILABLE", Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
});
}
@Override
public int getItemCount() {
return skuDetailsList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView txt_product_name, txt_price , txt_description ;
IRecylerClickListener listener;
public void setListener(IRecylerClickListener listener) {
this.listener = listener;
}
public MyViewHolder(@NonNull View itemView) {
super(itemView);
txt_price = itemView.findViewById(R.id.txt_pricealtin);
txt_product_name = itemView.findViewById(R.id.txt_product_namealtin);
itemView.setOnClickListener(this);
}
public void onClick(View view){
listener.onClick(view,getAdapterPosition());
}
}